summaryrefslogtreecommitdiffstats
path: root/src/jogl/classes/jogamp/opengl/GLContextImpl.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/jogl/classes/jogamp/opengl/GLContextImpl.java')
-rw-r--r--src/jogl/classes/jogamp/opengl/GLContextImpl.java1872
1 files changed, 1437 insertions, 435 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java
index 51201b3a9..9ccd78589 100644
--- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java
+++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.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,39 +29,51 @@
* 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.
*/
package jogamp.opengl;
+import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
+import java.security.AccessController;
+import java.security.PrivilegedAction;
import java.util.HashMap;
import java.util.Map;
import com.jogamp.common.os.DynamicLookupHelper;
+import com.jogamp.common.os.Platform;
import com.jogamp.common.util.ReflectionUtil;
-import com.jogamp.gluegen.runtime.FunctionAddressResolver;
+import com.jogamp.common.util.VersionNumber;
+import com.jogamp.common.util.VersionNumberString;
+import com.jogamp.common.util.locks.RecursiveLock;
import com.jogamp.gluegen.runtime.ProcAddressTable;
-import com.jogamp.gluegen.runtime.opengl.GLExtensionNames;
+import com.jogamp.gluegen.runtime.opengl.GLNameResolver;
import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver;
+import com.jogamp.opengl.GLExtensions;
+import com.jogamp.opengl.GLRendererQuirks;
import javax.media.nativewindow.AbstractGraphicsConfiguration;
import javax.media.nativewindow.AbstractGraphicsDevice;
import javax.media.nativewindow.NativeSurface;
+import javax.media.nativewindow.NativeWindowFactory;
import javax.media.opengl.GL;
-import javax.media.opengl.GL3;
+import javax.media.opengl.GL2ES2;
+import javax.media.opengl.GL2ES3;
+import javax.media.opengl.GL2GL3;
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.GLDrawableFactory;
import javax.media.opengl.GLException;
import javax.media.opengl.GLPipelineFactory;
import javax.media.opengl.GLProfile;
@@ -74,7 +86,7 @@ public abstract class GLContextImpl extends GLContext {
private String contextFQN;
private int additionalCtxCreationFlags;
-
+
// Cache of the functions that are available to be called at the current
// moment in time
protected ExtensionAvailabilityCache extensionAvailability;
@@ -82,19 +94,26 @@ public abstract class GLContextImpl extends GLContext {
// OpenGL functions.
private ProcAddressTable glProcAddressTable;
+ private String glVendor;
private String glRenderer;
private String glRendererLowerCase;
-
- // Tracks creation and initialization of buffer objects to avoid
+ private String glVersion;
+
+ // Tracks lifecycle of buffer objects to avoid
// repeated glGet calls upon glMapBuffer operations
- private GLBufferSizeTracker bufferSizeTracker; // Singleton - Set by GLContextShareSet
- private GLBufferStateTracker bufferStateTracker = new GLBufferStateTracker();
- private GLStateTracker glStateTracker = new GLStateTracker();
+ private final GLBufferObjectTracker bufferObjectTracker;
+ private final GLBufferStateTracker bufferStateTracker;
+ private final GLStateTracker glStateTracker = new GLStateTracker();
private GLDebugMessageHandler glDebugHandler = null;
-
+ private final int[] boundFBOTarget = new int[] { 0, 0 }; // { draw, read }
+ private int defaultVAO = 0;
+
protected GLDrawableImpl drawable;
protected GLDrawableImpl drawableRead;
+ private volatile boolean pixelDataEvaluated;
+ private int /* pixelDataInternalFormat, */ pixelDataFormat, pixelDataType;
+
protected GL gl;
protected static final Object mappedContextTypeObjectLock;
@@ -112,72 +131,128 @@ public abstract class GLContextImpl extends GLContext {
public static void shutdownImpl() {
mappedExtensionAvailabilityCache.clear();
mappedGLProcAddress.clear();
- mappedGLXProcAddress.clear();
+ mappedGLXProcAddress.clear();
}
-
+
public GLContextImpl(GLDrawableImpl drawable, GLContext shareWith) {
super();
- if (shareWith != null) {
+ bufferStateTracker = new GLBufferStateTracker();
+ if ( null != shareWith ) {
GLContextShareSet.registerSharing(this, shareWith);
+ bufferObjectTracker = ((GLContextImpl)shareWith).getBufferObjectTracker();
+ assert (bufferObjectTracker != null) : "shared context hash null GLBufferObjectTracker: "+shareWith;
+ } else {
+ bufferObjectTracker = new GLBufferObjectTracker();
}
- GLContextShareSet.synchronizeBufferObjectSharing(shareWith, this);
this.drawable = drawable;
this.drawableRead = drawable;
-
+
this.glDebugHandler = new GLDebugMessageHandler(this);
}
- @Override
- protected void resetStates() {
- // Because we don't know how many other contexts we might be
- // sharing with (and it seems too complicated to implement the
- // GLObjectTracker's ref/unref scheme for the buffer-related
- // optimizations), simply clear the cache of known buffers' sizes
- // when we destroy contexts
- if (bufferSizeTracker != null) {
- bufferSizeTracker.clearCachedBufferSizes();
- }
-
- if (bufferStateTracker != null) {
- bufferStateTracker.clearBufferObjectState();
+ private final void clearStates() {
+ if( !GLContextShareSet.hasCreatedSharedLeft(this) ) {
+ bufferObjectTracker.clear();
}
+ bufferStateTracker.clear();
+ glStateTracker.setEnabled(false);
+ glStateTracker.clearStates();
+ }
- if (glStateTracker != null) {
- glStateTracker.clearStates(false);
+ @Override
+ protected void resetStates(boolean isInit) {
+ if( !isInit ) {
+ clearStates();
}
-
extensionAvailability = null;
glProcAddressTable = null;
gl = null;
contextFQN = null;
additionalCtxCreationFlags = 0;
- glRenderer = "";
+ glVendor = "";
+ glRenderer = glVendor;
glRendererLowerCase = glRenderer;
-
- super.resetStates();
+ glVersion = glVendor;
+
+ if (boundFBOTarget != null) { // <init>
+ boundFBOTarget[0] = 0; // draw
+ boundFBOTarget[1] = 0; // read
+ }
+
+ pixelDataEvaluated = false;
+
+ super.resetStates(isInit);
}
- public final void setGLReadDrawable(GLDrawable read) {
- if(null!=read && drawable!=read && !isGLReadDrawableAvailable()) {
- throw new GLException("GL Read Drawable not available");
+ @Override
+ public final GLDrawable setGLReadDrawable(GLDrawable read) {
+ if(!isGLReadDrawableAvailable()) {
+ throw new GLException("Setting read drawable feature not available");
}
- boolean lockHeld = lock.isOwner();
+ final boolean lockHeld = lock.isOwner(Thread.currentThread());
if(lockHeld) {
release();
+ } else if(lock.isLockedByOtherThread()) { // still could glitch ..
+ throw new GLException("GLContext current by other thread ("+lock.getOwner()+"), operation not allowed.");
}
+ final GLDrawable old = drawableRead;
drawableRead = ( null != read ) ? (GLDrawableImpl) read : drawable;
if(lockHeld) {
makeCurrent();
}
+ return old;
}
+ @Override
public final GLDrawable getGLReadDrawable() {
return drawableRead;
}
+ @Override
+ public final GLDrawable setGLDrawable(GLDrawable readWrite, boolean setWriteOnly) {
+ if( drawable == readWrite && ( setWriteOnly || drawableRead == readWrite ) ) {
+ return drawable; // no change.
+ }
+ final Thread currentThread = Thread.currentThread();
+ if( lock.isLockedByOtherThread() ) {
+ throw new GLException("GLContext current by other thread "+lock.getOwner().getName()+", operation not allowed on this thread "+currentThread.getName());
+ }
+ final boolean lockHeld = lock.isOwner(currentThread);
+ if( lockHeld && lock.getHoldCount() > 1 ) {
+ // would need to makeCurrent * holdCount
+ throw new GLException("GLContext is recursively locked - unsupported for setGLDrawable(..)");
+ }
+ final GLDrawableImpl old = drawable;
+ if( isCreated() && null != old && old.isRealized() ) {
+ if(!lockHeld) {
+ makeCurrent();
+ }
+ associateDrawable(false);
+ if(!lockHeld) {
+ release();
+ }
+ }
+ if(lockHeld) {
+ release();
+ }
+ if( !setWriteOnly || drawableRead == drawable ) { // if !setWriteOnly || !explicitReadDrawable
+ drawableRead = (GLDrawableImpl) readWrite;
+ }
+ drawableRetargeted |= null != drawable && readWrite != drawable;
+ drawable = (GLDrawableImpl) readWrite ;
+ if( isCreated() && null != drawable && drawable.isRealized() ) {
+ makeCurrent(true); // implicit: associateDrawable(true)
+ if( !lockHeld ) {
+ release();
+ }
+ }
+ return old;
+ }
+
+ @Override
public final GLDrawable getGLDrawable() {
return drawable;
}
@@ -186,30 +261,48 @@ public abstract class GLContextImpl extends GLContext {
return (GLDrawableImpl) getGLDrawable();
}
+ @Override
+ public final GL getRootGL() {
+ GL _gl = gl;
+ GL _parent = _gl.getDownstreamGL();
+ while ( null != _parent ) {
+ _gl = _parent;
+ _parent = _gl.getDownstreamGL();
+ }
+ return _gl;
+ }
+
+ @Override
public final GL getGL() {
return gl;
}
+ @Override
public GL setGL(GL gl) {
- if(DEBUG) {
- String sgl1 = (null!=this.gl)?this.gl.getClass().getSimpleName()+", "+this.gl.toString():"<null>";
- String sgl2 = (null!=gl)?gl.getClass().getSimpleName()+", "+gl.toString():"<null>";
- Exception e = new Exception("Info: setGL (OpenGL "+getGLVersion()+"): "+Thread.currentThread().getName()+", "+sgl1+" -> "+sgl2);
- e.printStackTrace();
+ if( DEBUG ) {
+ final String sgl1 = (null!=this.gl)?this.gl.getClass().getSimpleName()+", "+this.gl.toString():"<null>";
+ final String sgl2 = (null!=gl)?gl.getClass().getSimpleName()+", "+gl.toString():"<null>";
+ System.err.println("Info: setGL (OpenGL "+getGLVersion()+"): "+getThreadName()+", "+sgl1+" -> "+sgl2);
+ Thread.dumpStack();
}
this.gl = gl;
return gl;
}
+ @Override
+ public final int getDefaultVAO() {
+ return defaultVAO;
+ }
+
/**
* Call this method to notify the OpenGL context
* that the drawable has changed (size or position).
- *
+ *
* <p>
- * This is currently being used and overridden by Mac OSX,
+ * This is currently being used and overridden by Mac OSX,
* which issues the {@link jogamp.opengl.macosx.cgl.CGL#updateContext(long) NSOpenGLContext update()} call.
* </p>
- *
+ *
* @throws GLException
*/
protected void drawableUpdatedNotify() throws GLException { }
@@ -217,22 +310,40 @@ public abstract class GLContextImpl extends GLContext {
public abstract Object getPlatformGLExtensions();
// Note: the surface is locked within [makeCurrent .. swap .. release]
+ @Override
public void release() throws GLException {
release(false);
}
- private void release(boolean force) throws GLException {
- if(TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: - release() - force: "+force+", "+lock);
+ private void release(boolean inDestruction) throws GLException {
+ if( TRACE_SWITCH ) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch[release.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+", inDestruction: "+inDestruction+", "+lock);
}
- if ( !lock.isOwner() ) {
- throw new GLException("Context not current on current thread "+Thread.currentThread().getName()+": "+this);
+ if ( !lock.isOwner(Thread.currentThread()) ) {
+ final String msg = getThreadName() +": Context not current on thread, obj " + toHexString(hashCode())+", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+", inDestruction: "+inDestruction+", "+lock;
+ if( DEBUG_TRACE_SWITCH ) {
+ System.err.println(msg);
+ if( null != lastCtxReleaseStack ) {
+ System.err.print("Last release call: ");
+ lastCtxReleaseStack.printStackTrace();
+ } else {
+ System.err.println("Last release call: NONE");
+ }
+ }
+ throw new GLException(msg);
}
- final boolean actualRelease = force || lock.getHoldCount() == 1 ;
- try {
+
+ Throwable drawableContextMadeCurrentException = null;
+ final boolean actualRelease = ( inDestruction || lock.getHoldCount() == 1 ) && 0 != contextHandle;
+ try {
if( actualRelease ) {
- if (contextHandle != 0) { // allow dbl-release
- releaseImpl();
+ if( !inDestruction ) {
+ try {
+ contextMadeCurrent(false);
+ } catch (Throwable t) {
+ drawableContextMadeCurrentException = t;
+ }
}
+ releaseImpl();
}
} finally {
// exception prone ..
@@ -241,68 +352,106 @@ public abstract class GLContextImpl extends GLContext {
}
drawable.unlockSurface();
lock.unlock();
- if(TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: - "+(actualRelease?"switch":"keep ")+" - CONTEXT_RELEASE - "+lock);
+ if( DEBUG_TRACE_SWITCH ) {
+ final String msg = getThreadName() +": GLContext.ContextSwitch[release.X]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+(actualRelease?"switch":"keep ")+" - "+lock;
+ lastCtxReleaseStack = new Throwable(msg);
+ if( TRACE_SWITCH ) {
+ System.err.println(msg);
+ // Thread.dumpStack();
+ }
}
}
+ if(null != drawableContextMadeCurrentException) {
+ throw new GLException("GLContext.release(false) during GLDrawableImpl.contextMadeCurrent(this, false)", drawableContextMadeCurrentException);
+ }
+
}
+ private Throwable lastCtxReleaseStack = null;
protected abstract void releaseImpl() throws GLException;
+ @Override
public final void destroy() {
- if (DEBUG || TRACE_SWITCH) {
- System.err.println(getThreadName() + ": GLContextImpl.destroy.0: " + toHexString(contextHandle) +
- ", isShared "+GLContextShareSet.isShared(this)+" - "+lock);
+ if ( DEBUG_TRACE_SWITCH ) {
+ final long drawH = null != drawable ? drawable.getHandle() : 0;
+ System.err.println(getThreadName() + ": GLContextImpl.destroy.0: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) +
+ ", surf "+toHexString(drawH)+", isShared "+GLContextShareSet.isShared(this)+" - "+lock);
}
- if (contextHandle != 0) {
- int lockRes = drawable.lockSurface();
- if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) {
+ if ( 0 != contextHandle ) { // isCreated() ?
+ if ( null == drawable ) {
+ throw new GLException("GLContext created but drawable is null: "+toString());
+ }
+ final int lockRes = drawable.lockSurface();
+ if ( NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes ) {
// this would be odd ..
throw new GLException("Surface not ready to lock: "+drawable);
}
+ Throwable associateDrawableException = null;
try {
+ if ( !drawable.isRealized() ) {
+ throw new GLException("GLContext created but drawable not realized: "+toString());
+ }
// Must hold the lock around the destroy operation to make sure we
// don't destroy the context while another thread renders to it.
- // FIXME: This is actually impossible now, since we acquired the surface lock already,
- // which is a prerequisite to acquire the context lock.
- lock.lock(); // holdCount++ -> 1 or 2
+ lock.lock(); // holdCount++ -> 1 - n (1: not locked, 2-n: destroy while rendering)
if ( lock.getHoldCount() > 2 ) {
- throw new GLException(getThreadName() + ": Lock was hold more than once - makeCurrent/release imbalance: "+lock);
+ final String msg = getThreadName() + ": GLContextImpl.destroy: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle);
+ if ( DEBUG_TRACE_SWITCH ) {
+ System.err.println(msg+" - Lock was hold more than once - makeCurrent/release imbalance: "+lock);
+ Thread.dumpStack();
+ }
}
- try {
- // release current context
- if(null != glDebugHandler) {
- if(lock.getHoldCount() == 1) {
- // needs current context to disable debug handler
- makeCurrent();
+ try {
+ // if not current, makeCurrent(), to call associateDrawable(..) and to disable debug handler
+ if ( lock.getHoldCount() == 1 ) {
+ if ( GLContext.CONTEXT_NOT_CURRENT == makeCurrent() ) {
+ throw new GLException("GLContext.makeCurrent() failed: "+toString());
}
- glDebugHandler.enable(false);
}
+ try {
+ associateDrawable(false);
+ } catch (Throwable t) {
+ associateDrawableException = t;
+ }
+ if ( 0 != defaultVAO ) {
+ final int[] tmp = new int[] { defaultVAO };
+ final GL2ES3 gl2es3 = gl.getRootGL().getGL2ES3();
+ gl2es3.glBindVertexArray(0);
+ gl2es3.glDeleteVertexArrays(1, tmp, 0);
+ defaultVAO = 0;
+ }
+ glDebugHandler.enable(false);
if(lock.getHoldCount() > 1) {
// pending release() after makeCurrent()
- release(true);
+ release(true);
}
destroyImpl();
contextHandle = 0;
glDebugHandler = null;
// this maybe impl. in a platform specific way to release remaining shared ctx.
- if(GLContextShareSet.contextDestroyed(this) && !GLContextShareSet.hasCreatedSharedLeft(this)) {
+ if( GLContextShareSet.contextDestroyed(this) && !GLContextShareSet.hasCreatedSharedLeft(this) ) {
GLContextShareSet.unregisterSharing(this);
}
+ resetStates(false);
} finally {
lock.unlock();
- if (TRACE_SWITCH) {
- System.err.println(getThreadName() + ": GLContextImpl.destroy.X: " + toHexString(contextHandle) +
+ if ( DEBUG_TRACE_SWITCH ) {
+ System.err.println(getThreadName() + ": GLContextImpl.destroy.X: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) +
", isShared "+GLContextShareSet.isShared(this)+" - "+lock);
}
}
} finally {
drawable.unlockSurface();
}
+ if( null != associateDrawableException ) {
+ throw new GLException("Exception @ destroy's associateDrawable(false)", associateDrawableException);
+ }
+ } else {
+ resetStates(false);
}
- resetStates();
}
protected abstract void destroyImpl() throws GLException;
+ @Override
public final void copy(GLContext source, int mask) throws GLException {
if (source.getHandle() == 0) {
throw new GLException("Source OpenGL context has not been created");
@@ -311,8 +460,8 @@ public abstract class GLContextImpl extends GLContext {
throw new GLException("Destination OpenGL context has not been created");
}
- int lockRes = drawable.lockSurface();
- if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) {
+ final int lockRes = drawable.lockSurface();
+ if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
// this would be odd ..
throw new GLException("Surface not ready to lock");
}
@@ -364,98 +513,110 @@ public abstract class GLContextImpl extends GLContext {
* @see #mapVersionAvailable
* @see #destroyContextARBImpl
*/
- public int makeCurrent() throws GLException {
- boolean unlockContextAndDrawable = false;
- int res = CONTEXT_NOT_CURRENT;
+ @Override
+ public final int makeCurrent() throws GLException {
+ return makeCurrent(false);
+ }
+
+ protected final int makeCurrent(boolean forceDrawableAssociation) throws GLException {
+ if( TRACE_SWITCH ) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.0]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - "+lock);
+ }
// Note: the surface is locked within [makeCurrent .. swap .. release]
- int lockRes = drawable.lockSurface();
+ final int lockRes = drawable.lockSurface();
if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) {
+ if( DEBUG_TRACE_SWITCH ) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X1]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - Surface Not Ready - CONTEXT_NOT_CURRENT - "+lock);
+ }
return CONTEXT_NOT_CURRENT;
}
+
+ boolean unlockResources = true; // Must be cleared if successful, otherwise finally block will release context and/or surface!
+ int res = CONTEXT_NOT_CURRENT;
try {
- if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) {
- drawable.updateHandle();
- }
-
- lock.lock();
- try {
- // One context can only be current by one thread,
- // and one thread can only have one context current!
- final GLContext current = getCurrent();
- if (current != null) {
- if (current == this) {
- // Assume we don't need to make this context current again
- // For Mac OS X, however, we need to update the context to track resizes
- drawableUpdatedNotify();
- if(TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: - keep - CONTEXT_CURRENT - "+lock);
- }
- return CONTEXT_CURRENT;
- } else {
- current.release();
- }
- }
- if (0 == drawable.getHandle()) {
+ if ( drawable.isRealized() ) {
+ if ( 0 == drawable.getHandle() ) {
throw new GLException("drawable has invalid handle: "+drawable);
}
- res = makeCurrentWithinLock(lockRes);
- unlockContextAndDrawable = CONTEXT_NOT_CURRENT == res;
-
- /**
- * FIXME: refactor dependence on Java 2D / JOGL bridge
- if ((tracker != null) &&
- (res == CONTEXT_CURRENT_NEW)) {
- // Increase reference count of GLObjectTracker
- tracker.ref();
+ lock.lock();
+ try {
+ // One context can only be current by one thread,
+ // and one thread can only have one context current!
+ final GLContext current = getCurrent();
+ if (current != null) {
+ if (current == this) { // implicit recursive locking!
+ // Assume we don't need to make this context current again
+ // For Mac OS X, however, we need to update the context to track resizes
+ drawableUpdatedNotify();
+ unlockResources = false; // success
+ if( TRACE_SWITCH ) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X2]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - keep - CONTEXT_CURRENT - "+lock);
+ }
+ return CONTEXT_CURRENT;
+ } else {
+ current.release();
+ }
}
- */
- } catch (RuntimeException e) {
- unlockContextAndDrawable = true;
- throw e;
- } finally {
- if (unlockContextAndDrawable) {
- lock.unlock();
- }
- }
+ res = makeCurrentWithinLock(lockRes);
+ unlockResources = CONTEXT_NOT_CURRENT == res; // success ?
+
+ /**
+ * FIXME: refactor dependence on Java 2D / JOGL bridge
+ if ( tracker != null && res == CONTEXT_CURRENT_NEW ) {
+ // Increase reference count of GLObjectTracker
+ tracker.ref();
+ }
+ */
+ } catch (RuntimeException e) {
+ unlockResources = true;
+ throw e;
+ } finally {
+ if (unlockResources) {
+ if( DEBUG_TRACE_SWITCH ) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.1]: Context lock.unlock() due to error, res "+makeCurrentResultToString(res)+", "+lock);
+ }
+ lock.unlock();
+ }
+ }
+ } /* if ( drawable.isRealized() ) */
} catch (RuntimeException e) {
- unlockContextAndDrawable = true;
+ unlockResources = true;
throw e;
} finally {
- if (unlockContextAndDrawable) {
+ if (unlockResources) {
drawable.unlockSurface();
- }
- }
-
- if (res == CONTEXT_NOT_CURRENT) {
- if(TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: - switch - CONTEXT_NOT_CURRENT - "+lock);
}
- } else {
+ }
+
+ if (res != CONTEXT_NOT_CURRENT) {
setCurrent(this);
if(res == CONTEXT_CURRENT_NEW) {
// check if the drawable's and the GL's GLProfile are equal
- // throws an GLException if not
+ // throws an GLException if not
getGLDrawable().getGLProfile().verifyEquality(gl.getGLProfile());
-
+
glDebugHandler.init( isGL2GL3() && isGLDebugEnabled() );
if(DEBUG_GL) {
- gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, gl, null) );
+ setGL( GLPipelineFactory.create("javax.media.opengl.Debug", null, gl, null) );
if(glDebugHandler.isEnabled()) {
glDebugHandler.addListener(new GLDebugMessageHandler.StdErrGLDebugListener(true));
}
}
if(TRACE_GL) {
- gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) );
- }
- if(DEBUG || TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: - switch - CONTEXT_CURRENT_NEW - "+lock);
+ setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) );
}
- } else if(TRACE_SWITCH) {
- System.err.println(getThreadName() +": GLContext.ContextSwitch: - switch - CONTEXT_CURRENT - "+lock);
+
+ forceDrawableAssociation = true;
}
+ if( forceDrawableAssociation ) {
+ associateDrawable(true);
+ }
+
+ contextMadeCurrent(true);
+
/* FIXME: refactor dependence on Java 2D / JOGL bridge
// Try cleaning up any stale server-side OpenGL objects
@@ -465,68 +626,94 @@ public abstract class GLContextImpl extends GLContext {
}
*/
}
+ if( TRACE_SWITCH ) {
+ System.err.println(getThreadName() +": GLContext.ContextSwitch[makeCurrent.X3]: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+", surf "+toHexString(drawable.getHandle())+" - switch - "+makeCurrentResultToString(res)+" - stateTracker.on "+glStateTracker.isEnabled()+" - "+lock);
+ }
return res;
}
private final int makeCurrentWithinLock(int surfaceLockRes) throws GLException {
if (!isCreated()) {
+ if( 0 >= drawable.getWidth() || 0 >= drawable.getHeight() ) {
+ if ( DEBUG_TRACE_SWITCH ) {
+ System.err.println(getThreadName() + ": Create GL context REJECTED (zero surface size) obj " + toHexString(hashCode()) + ", surf "+toHexString(drawable.getHandle())+" for " + getClass().getName());
+ System.err.println(drawable.toString());
+ }
+ return CONTEXT_NOT_CURRENT;
+ }
if(DEBUG_GL) {
// only impacts w/ createContextARB(..)
additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ;
}
-
- final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getShareContext(this);
+
+ final GLContextImpl shareWith = (GLContextImpl) GLContextShareSet.getCreatedShare(this);
+ final long shareWithHandle;
if (null != shareWith) {
shareWith.getDrawableImpl().lockSurface();
+ shareWithHandle = shareWith.getHandle();
+ if (0 == shareWithHandle) {
+ throw new GLException("GLContextShareSet returned an invalid OpenGL context: "+this);
+ }
+ } else {
+ shareWithHandle = 0;
}
final boolean created;
try {
- created = createImpl(shareWith); // may throws exception if fails!
+ created = createImpl(shareWithHandle); // may throws exception if fails
+ if( created && hasNoDefaultVAO() ) {
+ final int[] tmp = new int[1];
+ final GL rootGL = gl.getRootGL();
+ if( rootGL.isGL2ES3() ) { // FIXME remove if ES2 == ES3 later
+ final GL2ES3 gl2es3 = rootGL.getGL2ES3();
+ gl2es3.glGenVertexArrays(1, tmp, 0);
+ defaultVAO = tmp[0];
+ gl2es3.glBindVertexArray(defaultVAO);
+ }
+ }
} finally {
if (null != shareWith) {
shareWith.getDrawableImpl().unlockSurface();
- }
+ }
}
- if (DEBUG) {
+ if ( DEBUG_TRACE_SWITCH ) {
if(created) {
- System.err.println(getThreadName() + ": Create GL context OK: " + toHexString(contextHandle) + " for " + getClass().getName()+" - "+getGLVersion());
+ System.err.println(getThreadName() + ": Create GL context OK: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) + ", surf "+toHexString(drawable.getHandle())+" for " + getClass().getName()+" - "+getGLVersion());
+ // Thread.dumpStack();
} else {
- System.err.println(getThreadName() + ": Create GL context FAILED for " + getClass().getName());
+ System.err.println(getThreadName() + ": Create GL context FAILED obj " + toHexString(hashCode()) + ", surf "+toHexString(drawable.getHandle())+" for " + getClass().getName());
}
- }
+ }
if(!created) {
return CONTEXT_NOT_CURRENT;
}
-
+
// finalize mapping the available GLVersions, in case it's not done yet
- {
+ {
final AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration();
final AbstractGraphicsDevice device = config.getScreen().getDevice();
-
- if( !GLContext.getAvailableGLVersionsSet(device) ) {
- final int reqMajor;
- final int reqProfile;
- if( 0 != ( ctxOptions & GLContext.CTX_PROFILE_ES) ) {
- // ES1 or ES2
- reqMajor = ctxMajorVersion;
- reqProfile = GLContext.CTX_PROFILE_ES;
- } else {
- if(ctxMajorVersion<3 || ctxMajorVersion==3 && ctxMinorVersion==0) {
+
+ // Non ARB desktop profiles may not have been registered
+ if( !GLContext.getAvailableGLVersionsSet(device) ) { // not yet set
+ if( 0 == ( ctxOptions & GLContext.CTX_PROFILE_ES) ) { // not ES profile
+ final int reqMajor;
+ final int reqProfile;
+ if( ctxVersion.compareTo(Version300) <= 0 ) {
reqMajor = 2;
} else {
- reqMajor = ctxMajorVersion;
+ reqMajor = ctxVersion.getMajor();
}
if( 0 != ( ctxOptions & GLContext.CTX_PROFILE_CORE) ) {
reqProfile = GLContext.CTX_PROFILE_CORE;
} else {
reqProfile = GLContext.CTX_PROFILE_COMPAT;
}
- }
- GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile,
- ctxMajorVersion, ctxMinorVersion, ctxOptions);
- GLContext.setAvailableGLVersionsSet(device);
- if (DEBUG) {
- System.err.println(getThreadName() + ": createContextOLD-MapVersionsAvailable HAVE: " + device+" -> "+reqMajor+"."+reqProfile+ " -> "+getGLVersion());
+ GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile,
+ ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ GLContext.setAvailableGLVersionsSet(device);
+
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": createContextOLD-MapVersionsAvailable HAVE: " + device+" -> "+reqMajor+"."+reqProfile+ " -> "+getGLVersion());
+ }
}
}
}
@@ -537,30 +724,44 @@ public abstract class GLContextImpl extends GLContext {
return CONTEXT_CURRENT;
}
protected abstract void makeCurrentImpl() throws GLException;
-
- /**
+
+ /**
+ * Calls {@link GLDrawableImpl#associateContext(GLContext, boolean)}
+ */
+ protected void associateDrawable(boolean bound) {
+ drawable.associateContext(this, bound);
+ }
+
+ /**
+ * Calls {@link GLDrawableImpl#contextMadeCurrent(GLContext, boolean)}
+ */
+ protected void contextMadeCurrent(boolean current) {
+ drawable.contextMadeCurrent(this, current);
+ }
+
+ /**
* Platform dependent entry point for context creation.<br>
*
* This method is called from {@link #makeCurrentWithinLock()} .. {@link #makeCurrent()} .<br>
*
- * The implementation shall verify this context with a
+ * The implementation shall verify this context with a
* <code>MakeContextCurrent</code> call.<br>
*
* The implementation <b>must</b> leave the context current.<br>
- *
+ *
* @param share the shared context or null
* @return the valid and current context if successful, or null
* @throws GLException
*/
- protected abstract boolean createImpl(GLContextImpl sharedWith) throws GLException ;
+ protected abstract boolean createImpl(long sharedWithHandle) throws GLException ;
- /**
+ /**
* Platform dependent but harmonized implementation of the <code>ARB_create_context</code>
* mechanism to create a context.<br>
*
- * This method is called from {@link #createContextARB}, {@link #createImpl(GLContextImpl)} .. {@link #makeCurrent()} .<br>
+ * This method is called from {@link #createContextARB}, {@link #createImpl(long)} .. {@link #makeCurrent()} .<br>
*
- * The implementation shall verify this context with a
+ * The implementation shall verify this context with a
* <code>MakeContextCurrent</code> call.<br>
*
* The implementation <b>must</b> leave the context current.<br>
@@ -582,8 +783,7 @@ public abstract class GLContextImpl extends GLContext {
* @see #createContextARBImpl
* @see #destroyContextARBImpl
*/
- protected abstract long createContextARBImpl(long share, boolean direct, int ctxOptionFlags,
- int major, int minor);
+ protected abstract long createContextARBImpl(long share, boolean direct, int ctxOptionFlags, int major, int minor);
/**
* Destroy the context created by {@link #createContextARBImpl}.
@@ -616,13 +816,10 @@ public abstract class GLContextImpl extends GLContext {
* @see #createContextARBImpl
* @see #destroyContextARBImpl
*/
- protected final long createContextARB(long share, boolean direct)
+ protected final long createContextARB(final long share, final boolean direct)
{
- AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration();
- AbstractGraphicsDevice device = config.getScreen().getDevice();
- GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
- GLProfile glp = glCaps.getGLProfile();
- GLProfile glpImpl = glp.getImpl();
+ final AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration();
+ final AbstractGraphicsDevice device = config.getScreen().getDevice();
if (DEBUG) {
System.err.println(getThreadName() + ": createContextARB: mappedVersionsAvailableSet("+device.getConnection()+"): "+
@@ -631,64 +828,166 @@ public abstract class GLContextImpl extends GLContext {
if ( !GLContext.getAvailableGLVersionsSet(device) ) {
if(!mapGLVersions(device)) {
- // none of the ARB context creation calls was successful, bail out
+ // none of the ARB context creation calls was successful, bail out
return 0;
}
}
- int reqMajor;
- if(glpImpl.isGL4()) {
- reqMajor=4;
- } else if (glpImpl.isGL3()) {
- reqMajor=3;
- } else /* if (glpImpl.isGL2()) */ {
- reqMajor=2;
- }
+ final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities();
+ final int[] reqMajorCTP = new int[] { 0, 0 };
+ GLContext.getRequestMajorAndCompat(glCaps.getGLProfile(), reqMajorCTP);
- boolean compat = glpImpl.isGL2(); // incl GL3bc and GL4bc
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": createContextARB: Requested "+GLContext.getGLVersion(reqMajorCTP[0], 0, reqMajorCTP[0], null));
+ }
int _major[] = { 0 };
int _minor[] = { 0 };
int _ctp[] = { 0 };
long _ctx = 0;
-
- if( GLContext.getAvailableGLVersion(device, reqMajor, compat?CTX_PROFILE_COMPAT:CTX_PROFILE_CORE,
+ if( GLContext.getAvailableGLVersion(device, reqMajorCTP[0], reqMajorCTP[1],
_major, _minor, _ctp)) {
_ctp[0] |= additionalCtxCreationFlags;
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": createContextARB: Mapped "+GLContext.getGLVersion(_major[0], _minor[0], _ctp[0], null));
+ }
_ctx = createContextARBImpl(share, direct, _ctp[0], _major[0], _minor[0]);
if(0!=_ctx) {
- setGLFunctionAvailability(true, _major[0], _minor[0], _ctp[0]);
+ if( !setGLFunctionAvailability(true, _major[0], _minor[0], _ctp[0], false /* strictMatch */, false /* withinGLVersionsMapping */) ) {
+ throw new InternalError("setGLFunctionAvailability !strictMatch failed");
+ }
}
}
return _ctx;
}
- private final boolean mapGLVersions(AbstractGraphicsDevice device) {
+ private final boolean mapGLVersions(AbstractGraphicsDevice device) {
synchronized (GLContext.deviceVersionAvailable) {
+ final long t0 = ( DEBUG ) ? System.nanoTime() : 0;
boolean success = false;
// Following GLProfile.GL_PROFILE_LIST_ALL order of profile detection { GL4bc, GL3bc, GL2, GL4, GL3, GL2GL3, GLES2, GL2ES2, GLES1, GL2ES1 }
- success |= createContextARBMapVersionsAvailable(4, true /* compat */); // GL4bc
- success |= createContextARBMapVersionsAvailable(3, true /* compat */); // GL3bc
- success |= createContextARBMapVersionsAvailable(2, true /* compat */); // GL2
- success |= createContextARBMapVersionsAvailable(4, false /* core */); // GL4
- success |= createContextARBMapVersionsAvailable(3, false /* core */); // GL3
+ boolean hasGL4bc = false;
+ boolean hasGL3bc = false;
+ boolean hasGL2 = false;
+ boolean hasGL4 = false;
+ boolean hasGL3 = false;
+
+ // Even w/ PROFILE_ALIASING, try to use true core GL profiles
+ // ensuring proper user behavior across platforms due to different feature sets!
+ //
+ if( Platform.OSType.MACOS == Platform.getOSType() &&
+ Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 ) {
+ /**
+ * OSX 10.9 GLRendererQuirks.GL4NeedsGL3Request, quirk is added as usual @ setRendererQuirks(..)
+ */
+ if( !hasGL4 && !hasGL3 ) {
+ hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3
+ success |= hasGL3;
+ if( hasGL3 ) {
+ final boolean isHWAccel = 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions );
+ if( isHWAccel && ctxVersion.getMajor() >= 4 ) {
+ // Gotcha: Creating a '3.2' ctx delivers a >= 4 ctx.
+ GLContext.mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ hasGL4 = true;
+ if(DEBUG) {
+ System.err.println("Quirk Triggerd: "+GLRendererQuirks.toString(GLRendererQuirks.GL4NeedsGL3Request)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber());
+ }
+ }
+ resetStates(false); // clean this context states, since creation was temporary
+ }
+ }
+ }
+ if( !hasGL4 ) {
+ hasGL4 = createContextARBMapVersionsAvailable(4, CTX_PROFILE_CORE); // GL4
+ success |= hasGL4;
+ if( hasGL4 ) {
+ if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
+ // Map hw-accel GL4 to all lower core profiles: GL3
+ GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ if( PROFILE_ALIASING ) {
+ hasGL3 = true;
+ }
+ }
+ resetStates(false); // clean context states, since creation was temporary
+ }
+ }
+ if( !hasGL3 ) {
+ hasGL3 = createContextARBMapVersionsAvailable(3, CTX_PROFILE_CORE); // GL3
+ success |= hasGL3;
+ if( hasGL3 ) {
+ resetStates(false); // clean this context states, since creation was temporary
+ }
+ }
+ if( !hasGL4bc ) {
+ hasGL4bc = createContextARBMapVersionsAvailable(4, CTX_PROFILE_COMPAT); // GL4bc
+ success |= hasGL4bc;
+ if( hasGL4bc ) {
+ if( !hasGL4 ) { // last chance .. ignore hw-accel
+ GLContext.mapAvailableGLVersion(device, 4, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ hasGL4 = true;
+ }
+ if( !hasGL3 ) { // last chance .. ignore hw-accel
+ GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ hasGL3 = true;
+ }
+ if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
+ // Map hw-accel GL4bc to all lower compatible profiles: GL3bc, GL2
+ GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_COMPAT, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ GLContext.mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ if(PROFILE_ALIASING) {
+ hasGL3bc = true;
+ hasGL2 = true;
+ }
+ }
+ resetStates(false); // clean this context states, since creation was temporary
+ }
+ }
+ if( !hasGL3bc ) {
+ hasGL3bc = createContextARBMapVersionsAvailable(3, CTX_PROFILE_COMPAT); // GL3bc
+ success |= hasGL3bc;
+ if( hasGL3bc ) {
+ if(!hasGL3) { // last chance .. ignore hw-accel
+ GLContext.mapAvailableGLVersion(device, 3, CTX_PROFILE_CORE, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ hasGL3 = true;
+ }
+ if( 0 == ( CTX_IMPL_ACCEL_SOFT & ctxOptions ) ) {
+ // Map hw-accel GL3bc to all lower compatible profiles: GL2
+ GLContext.mapAvailableGLVersion(device, 2, CTX_PROFILE_COMPAT, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
+ if(PROFILE_ALIASING) {
+ hasGL2 = true;
+ }
+ }
+ resetStates(false); // clean this context states, since creation was temporary
+ }
+ }
+ if( !hasGL2 ) {
+ hasGL2 = createContextARBMapVersionsAvailable(2, CTX_PROFILE_COMPAT); // GL2
+ success |= hasGL2;
+ if( hasGL2 ) {
+ resetStates(false); // clean this context states, since creation was temporary
+ }
+ }
if(success) {
// only claim GL versions set [and hence detected] if ARB context creation was successful
GLContext.setAvailableGLVersionsSet(device);
+ if(DEBUG) {
+ final long t1 = System.nanoTime();
+ System.err.println("GLContextImpl.mapGLVersions: "+device+", profileAliasing: "+PROFILE_ALIASING+", total "+(t1-t0)/1e6 +"ms");
+ System.err.println(GLContext.dumpAvailableGLVersions(null).toString());
+ }
} else if (DEBUG) {
System.err.println(getThreadName() + ": createContextARB-MapVersions NONE for :"+device);
- }
+ }
return success;
}
}
- private final boolean createContextARBMapVersionsAvailable(int reqMajor, boolean compat) {
+ /**
+ * Note: Since context creation is temporary, caller need to issue {@link #resetStates(boolean)}, if creation was successful, i.e. returns true.
+ * This method does not reset the states, allowing the caller to utilize the state variables.
+ **/
+ private final boolean createContextARBMapVersionsAvailable(int reqMajor, int reqProfile) {
long _context;
- int reqProfile = compat ? CTX_PROFILE_COMPAT : CTX_PROFILE_CORE ;
- int ctp = CTX_IS_ARB_CREATED | CTX_PROFILE_CORE; // default
- if(compat) {
- ctp &= ~CTX_PROFILE_CORE ;
- ctp |= CTX_PROFILE_COMPAT ;
- }
+ int ctp = CTX_IS_ARB_CREATED | reqProfile;
// To ensure GL profile compatibility within the JOGL application
// we always try to map against the highest GL version,
@@ -698,104 +997,93 @@ public abstract class GLContextImpl extends GLContext {
int major[] = new int[1];
int minor[] = new int[1];
if( 4 == reqMajor ) {
- majorMax=4; minorMax=GLContext.getMaxMinor(majorMax);
+ majorMax=4; minorMax=GLContext.getMaxMinor(ctp, majorMax);
majorMin=4; minorMin=0;
} else if( 3 == reqMajor ) {
- majorMax=3; minorMax=GLContext.getMaxMinor(majorMax);
+ majorMax=3; minorMax=GLContext.getMaxMinor(ctp, majorMax);
majorMin=3; minorMin=1;
} else /* if( glp.isGL2() ) */ {
- // our minimum desktop OpenGL runtime requirements are 1.1,
- // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts
+ // our minimum desktop OpenGL runtime requirements are 1.1,
+ // nevertheless we restrict ARB context creation to 2.0 to spare us futile attempts
majorMax=3; minorMax=0;
majorMin=2; minorMin=0;
}
- _context = createContextARBVersions(0, true, ctp,
+ _context = createContextARBVersions(0, true, ctp,
/* max */ majorMax, minorMax,
/* min */ majorMin, minorMin,
/* res */ major, minor);
- if(0==_context && !compat) {
+ if( 0 == _context && CTX_PROFILE_CORE == reqProfile && !PROFILE_ALIASING ) {
// try w/ FORWARD instead of CORE
ctp &= ~CTX_PROFILE_CORE ;
ctp |= CTX_OPTION_FORWARD ;
- _context = createContextARBVersions(0, true, ctp,
+ _context = createContextARBVersions(0, true, ctp,
/* max */ majorMax, minorMax,
/* min */ majorMin, minorMin,
/* res */ major, minor);
- if(0==_context) {
+ if( 0 == _context ) {
// Try a compatible one .. even though not requested .. last resort
ctp &= ~CTX_PROFILE_CORE ;
ctp &= ~CTX_OPTION_FORWARD ;
ctp |= CTX_PROFILE_COMPAT ;
- _context = createContextARBVersions(0, true, ctp,
+ _context = createContextARBVersions(0, true, ctp,
/* max */ majorMax, minorMax,
/* min */ majorMin, minorMin,
/* res */ major, minor);
}
}
- if(0!=_context) {
- AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice();
- // ctxMajorVersion, ctxMinorVersion, ctxOptions is being set by
+ final boolean res;
+ if( 0 != _context ) {
+ AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice();
+ // ctxMajorVersion, ctxMinorVersion, ctxOptions is being set by
// createContextARBVersions(..) -> setGLFunctionAvailbility(..) -> setContextVersion(..)
- GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, ctxMajorVersion, ctxMinorVersion, ctxOptions);
+ GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions);
destroyContextARBImpl(_context);
if (DEBUG) {
System.err.println(getThreadName() + ": createContextARB-MapVersionsAvailable HAVE: " +reqMajor+"."+reqProfile+ " -> "+getGLVersion());
}
- // only reset [and hence modify] this context state if ARB context creation was successful
- resetStates();
- return true;
+ res = true;
} else {
if (DEBUG) {
System.err.println(getThreadName() + ": createContextARB-MapVersionsAvailable NOPE: "+reqMajor+"."+reqProfile);
- }
- return false;
+ }
+ res = false;
}
+ return res;
}
- private final long createContextARBVersions(long share, boolean direct, int ctxOptionFlags,
- int majorMax, int minorMax,
- int majorMin, int minorMin,
+ private final long createContextARBVersions(long share, boolean direct, int ctxOptionFlags,
+ int majorMax, int minorMax,
+ int majorMin, int minorMin,
int major[], int minor[]) {
major[0]=majorMax;
minor[0]=minorMax;
long _context=0;
- boolean ok = false;
-
- while ( !ok &&
- GLContext.isValidGLVersion(major[0], minor[0]) &&
- ( major[0]>majorMin || major[0]==majorMin && minor[0] >=minorMin ) ) {
+ int i=0;
+ do {
if (DEBUG) {
- System.err.println(getThreadName() + ": createContextARBVersions: share "+share+", direct "+direct+", version "+major[0]+"."+minor[0]);
+ i++;
+ System.err.println(getThreadName() + ": createContextARBVersions."+i+": share "+share+", direct "+direct+
+ ", version "+major[0]+"."+minor[0]+", major["+majorMin+".."+majorMax+"], minor["+minorMin+".."+minorMax+"]");
}
_context = createContextARBImpl(share, direct, ctxOptionFlags, major[0], minor[0]);
if(0 != _context) {
- ok = true;
- setGLFunctionAvailability(true, major[0], minor[0], ctxOptionFlags);
- } else {
- ok = false;
- }
-
- if(ok && major[0]>=3) {
- int[] hasMajor = new int[1]; int[] hasMinor = new int[1];
- gl.glGetIntegerv(GL3.GL_MAJOR_VERSION, hasMajor, 0);
- gl.glGetIntegerv(GL3.GL_MINOR_VERSION, hasMinor, 0);
- ok = hasMajor[0]>major[0] || ( hasMajor[0]==major[0] && hasMinor[0]>=minor[0] ) ;
- if(!ok) {
- removeCachedVersion(major[0], minor[0], ctxOptionFlags);
+ if( setGLFunctionAvailability(true, major[0], minor[0], ctxOptionFlags, true /* strictMatch */, true /* withinGLVersionsMapping */) ) {
+ break;
+ } else {
destroyContextARBImpl(_context);
_context = 0;
}
- if (DEBUG) {
- System.err.println(getThreadName() + ": createContextARBVersions: version verification - expected "+major[0]+"."+minor[0]+", has "+hasMajor[0]+"."+hasMinor[0]+" == "+ok);
- }
- }
-
- if(!ok) {
- if(!GLContext.decrementGLVersion(major, minor)) break;
}
+
+ } while ( ( major[0]>majorMin || major[0]==majorMin && minor[0] >minorMin ) && // #1 check whether version is above lower limit
+ GLContext.decrementGLVersion(ctxOptionFlags, major, minor) // #2 decrement version
+ );
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": createContextARBVersions.X: ctx "+toHexString(_context)+", share "+share+", direct "+direct+
+ ", version "+major[0]+"."+minor[0]+", major["+majorMin+".."+majorMax+"], minor["+minorMin+".."+minorMax+"]");
}
return _context;
}
@@ -805,52 +1093,31 @@ public abstract class GLContextImpl extends GLContext {
// As a last resort, the GL_VERSION string may be used ..
//
- /**
- * If major > 0 || minor > 0 : Use passed values, determined at creation time
- * If major==0 && minor == 0 : Use GL_VERSION
+ /**
+ * If major > 0 || minor > 0 : Use passed values, determined at creation time
* Otherwise .. don't touch ..
*/
- private final void setContextVersion(int major, int minor, int ctp, boolean setVersionString) {
- if (0==ctp) {
+ private final void setContextVersion(int major, int minor, int ctp, VersionNumberString glVendorVersion, boolean useGL) {
+ if ( 0 == ctp ) {
throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp));
}
- if(major>0 || minor>0) {
- if (!GLContext.isValidGLVersion(major, minor)) {
- GLException e = new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp));
- throw e;
- }
- ctxMajorVersion = major;
- ctxMinorVersion = minor;
- ctxOptions = ctp;
- if(setVersionString) {
- ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, getGL().glGetString(GL.GL_VERSION));
- }
- return;
- }
-
- if(major==0 && minor==0) {
- String versionStr = getGL().glGetString(GL.GL_VERSION);
- if(null==versionStr) {
- throw new GLException("GL_VERSION is NULL: "+this);
- }
- ctxOptions = ctp;
-
- // Set version
- GLVersionNumber version = new GLVersionNumber(versionStr);
- if (version.isValid()) {
- ctxMajorVersion = version.getMajor();
- ctxMinorVersion = version.getMinor();
- // We cannot promote a non ARB context to >= 3.1,
- // reduce it to 3.0 then.
- if ( ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 )
- && 0 == (ctxOptions & CTX_IS_ARB_CREATED) ) {
- ctxMajorVersion = 3;
- ctxMinorVersion = 0;
- }
- if(setVersionString) {
- ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, versionStr);
- }
- return;
+ ctxVersion = new VersionNumber(major, minor, 0);
+ ctxVersionString = getGLVersion(major, minor, ctp, glVersion);
+ ctxVendorVersion = glVendorVersion;
+ ctxOptions = ctp;
+ if(useGL) {
+ ctxGLSLVersion = VersionNumber.zeroVersion;
+ if( hasGLSL() ) { // >= ES2 || GL2.0
+ final String glslVersion = isGLES() ? null : gl.glGetString(GL2ES2.GL_SHADING_LANGUAGE_VERSION) ; // Use static GLSL version for ES to be safe!
+ if( null != glslVersion ) {
+ ctxGLSLVersion = new VersionNumber(glslVersion);
+ if( ctxGLSLVersion.getMajor() < 1 ) {
+ ctxGLSLVersion = VersionNumber.zeroVersion; // failed ..
+ }
+ }
+ if( ctxGLSLVersion.isZero() ) {
+ ctxGLSLVersion = getStaticGLSLVersionNumber(major, minor, ctxOptions);
+ }
}
}
}
@@ -859,18 +1126,18 @@ public abstract class GLContextImpl extends GLContext {
// Helpers for various context implementations
//
- private Object createInstance(GLProfile glp, String suffix, Class<?>[] cstrArgTypes, Object[] cstrArgs) {
- return ReflectionUtil.createInstance(glp.getGLImplBaseClassName()+suffix, cstrArgTypes, cstrArgs, getClass().getClassLoader());
+ private Object createInstance(GLProfile glp, boolean glObject, Object[] cstrArgs) {
+ return ReflectionUtil.createInstance(glp.getGLCtor(glObject), cstrArgs);
}
private boolean verifyInstance(GLProfile glp, String suffix, Object instance) {
- return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix);
+ return ReflectionUtil.instanceOf(instance, glp.getGLImplBaseClassName()+suffix);
}
/** Create the GL for this context. */
protected GL createGL(GLProfile glp) {
- GL gl = (GL) createInstance(glp, "Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { glp, this } );
-
+ final GL gl = (GL) createInstance(glp, true, new Object[] { glp, this } );
+
/* FIXME: refactor dependence on Java 2D / JOGL bridge
if (tracker != null) {
gl.setObjectTracker(tracker);
@@ -878,11 +1145,32 @@ public abstract class GLContextImpl extends GLContext {
*/
return gl;
}
-
+
+ /**
+ * Finalizes GL instance initialization after this context has been initialized.
+ * <p>
+ * Method calls 'void finalizeInit()' of instance 'gl' as retrieved by reflection, if exist.
+ * </p>
+ */
+ private void finalizeInit(GL gl) {
+ Method finalizeInit = null;
+ try {
+ finalizeInit = ReflectionUtil.getMethod(gl.getClass(), "finalizeInit", new Class<?>[]{ });
+ } catch ( Throwable t ) {
+ if(DEBUG) {
+ System.err.println("Catched "+t.getClass().getName()+": "+t.getMessage());
+ t.printStackTrace();
+ }
+ }
+ if( null != finalizeInit ) {
+ ReflectionUtil.callMethod(gl, finalizeInit, new Object[]{ });
+ }
+ }
+
public final ProcAddressTable getGLProcAddressTable() {
return glProcAddressTable;
}
-
+
/**
* Shall return the platform extension ProcAddressTable,
* ie for GLXExt, EGLExt, ..
@@ -890,18 +1178,22 @@ public abstract class GLContextImpl extends GLContext {
public abstract ProcAddressTable getPlatformExtProcAddressTable();
/**
- * Pbuffer support; given that this is a GLContext associated with a
- * pbuffer, binds this pbuffer to its texture target.
+ * Part of <code>GL_NV_vertex_array_range</code>.
+ * <p>
+ * Provides platform-independent access to the <code>wglAllocateMemoryNV</code> /
+ * <code>glXAllocateMemoryNV</code>.
+ * </p>
*/
- public abstract void bindPbufferToTexture();
+ public abstract ByteBuffer glAllocateMemoryNV(int size, float readFrequency, float writeFrequency, float priority);
/**
- * Pbuffer support; given that this is a GLContext associated with a
- * pbuffer, releases this pbuffer from its texture target.
+ * Part of <code>GL_NV_vertex_array_range</code>.
+ * <p>
+ * Provides platform-independent access to the <code>wglFreeMemoryNV</code> /
+ * <code>glXFreeMemoryNV</code>.
+ * </p>
*/
- public abstract void releasePbufferFromTexture();
-
- public abstract ByteBuffer glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3);
+ public abstract void glFreeMemoryNV(ByteBuffer pointer);
/** Maps the given "platform-independent" function name to a real function
name. Currently this is only used to map "glAllocateMemoryNV" and
@@ -918,8 +1210,8 @@ public abstract class GLContextImpl extends GLContext {
/** Maps the given "platform-independent" extension name to a real
function name. Currently this is only used to map
- "GL_ARB_pbuffer" to "WGL_ARB_pbuffer/GLX_SGIX_pbuffer" and
- "GL_ARB_pixel_format" to "WGL_ARB_pixel_format/n.a."
+ "GL_ARB_pbuffer" to "WGL_ARB_pbuffer/GLX_SGIX_pbuffer" and
+ "GL_ARB_pixel_format" to "WGL_ARB_pixel_format/n.a."
*/
protected final String mapToRealGLExtensionName(String glExtensionName) {
Map<String, String> map = getExtensionNameMap();
@@ -933,41 +1225,118 @@ public abstract class GLContextImpl extends GLContext {
/** Helper routine which resets a ProcAddressTable generated by the
GLEmitter by looking up anew all of its function pointers. */
- protected final void resetProcAddressTable(ProcAddressTable table) {
- table.reset(getDrawableImpl().getGLDynamicLookupHelper() );
+ protected final void resetProcAddressTable(final ProcAddressTable table) {
+ AccessController.doPrivileged(new PrivilegedAction<Object>() {
+ @Override
+ public Object run() {
+ table.reset(getDrawableImpl().getGLDynamicLookupHelper() );
+ return null;
+ }
+ } );
}
- private final void initGLRendererStrings() {
+ private final boolean initGLRendererAndGLVersionStrings() {
final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper();
final long _glGetString = glDynLookupHelper.dynamicLookupFunction("glGetString");
if(0 == _glGetString) {
- // FIXME
- System.err.println("Warning: Entry point to 'glGetString' is NULL.");
- Thread.dumpStack();
+ System.err.println("Error: Entry point to 'glGetString' is NULL.");
+ if(DEBUG) {
+ Thread.dumpStack();
+ }
+ return false;
} else {
+ final String _glVendor = glGetStringInt(GL.GL_VENDOR, _glGetString);
+ if(null == _glVendor) {
+ if(DEBUG) {
+ System.err.println("Warning: GL_VENDOR is NULL.");
+ Thread.dumpStack();
+ }
+ return false;
+ }
+ glVendor = _glVendor;
+
final String _glRenderer = glGetStringInt(GL.GL_RENDERER, _glGetString);
if(null == _glRenderer) {
+ if(DEBUG) {
+ System.err.println("Warning: GL_RENDERER is NULL.");
+ Thread.dumpStack();
+ }
+ return false;
+ }
+ glRenderer = _glRenderer;
+ glRendererLowerCase = glRenderer.toLowerCase();
+
+ final String _glVersion = glGetStringInt(GL.GL_VERSION, _glGetString);
+ if(null == _glVersion) {
// FIXME
- System.err.println("Warning: GL_RENDERER is NULL.");
- Thread.dumpStack();
- } else {
- glRenderer = _glRenderer;
- glRendererLowerCase = glRenderer.toLowerCase();
+ if(DEBUG) {
+ System.err.println("Warning: GL_VERSION is NULL.");
+ Thread.dumpStack();
+ }
+ return false;
+ }
+ glVersion = _glVersion;
+
+ return true;
+ }
+ }
+
+ /**
+ * Returns null if version string is invalid, otherwise a valid instance.
+ * <p>
+ * Note: Non ARB ctx is limited to GL 3.0.
+ * </p>
+ */
+ private static final VersionNumber getGLVersionNumber(int ctp, String glVersionStr) {
+ if( null != glVersionStr ) {
+ final GLVersionNumber version = GLVersionNumber.create(glVersionStr);
+ if ( version.isValid() ) {
+ int[] major = new int[] { version.getMajor() };
+ int[] minor = new int[] { version.getMinor() };
+ if ( GLContext.isValidGLVersion(ctp, major[0], minor[0]) ) {
+ return new VersionNumber(major[0], minor[0], 0);
+ }
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Returns false if <code>glGetIntegerv</code> is inaccessible, otherwise queries major.minor
+ * version for given arrays.
+ * <p>
+ * If the GL query fails, major will be zero.
+ * </p>
+ */
+ private final boolean getGLIntVersion(int[] glIntMajor, int[] glIntMinor) {
+ glIntMajor[0] = 0; // clear
+ final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper();
+ final long _glGetIntegerv = glDynLookupHelper.dynamicLookupFunction("glGetIntegerv");
+ if( 0 == _glGetIntegerv ) {
+ System.err.println("Error: Entry point to 'glGetIntegerv' is NULL.");
+ if(DEBUG) {
+ Thread.dumpStack();
}
+ return false;
+ } else {
+ glGetIntegervInt(GL2GL3.GL_MAJOR_VERSION, glIntMajor, 0, _glGetIntegerv);
+ glGetIntegervInt(GL2GL3.GL_MINOR_VERSION, glIntMinor, 0, _glGetIntegerv);
+ return true;
}
}
-
- protected final String getGLRendererString(boolean lowerCase) {
- return lowerCase ? glRendererLowerCase : glRenderer;
+
+ protected final int getCtxOptions() {
+ return ctxOptions;
}
-
+
+
/**
* Sets the OpenGL implementation class and
* the cache of which GL functions are available for calling through this
* context. See {@link #isFunctionAvailable(String)} for more information on
* the definition of "available".
* <br>
- * All ProcaddressTables are being determined, the GL version is being set
+ * All ProcaddressTables are being determined and cached, the GL version is being set
* and the extension cache is determined as well.
*
* @param force force the setting, even if is already being set.
@@ -975,33 +1344,227 @@ public abstract class GLContextImpl extends GLContext {
* @param major OpenGL major version
* @param minor OpenGL minor version
* @param ctxProfileBits OpenGL context profile and option bits, see {@link javax.media.opengl.GLContext#CTX_OPTION_ANY}
- *
+ * @param strictMatch if <code>true</code> the ctx must
+ * <ul>
+ * <li>be greater or equal than the requested <code>major.minor</code> version, and</li>
+ * <li>match the ctxProfileBits</li>
+ * <li>match ES major versions</li>
+ * </ul>, otherwise method aborts and returns <code>false</code>.<br>
+ * if <code>false</code> no version check is performed.
+ * @param withinGLVersionsMapping if <code>true</code> GL version mapping is in process, i.e. quering avail versions.
+ * Otherwise normal user context creation.
+ * @return returns <code>true</code> if successful, otherwise <code>false</code>.<br>
+ * If <code>strictMatch</code> is <code>false</code> method shall always return <code>true</code> or throw an exception.
+ * If <code>false</code> is returned, no data has been cached or mapped, i.e. ProcAddressTable, Extensions, Version, etc.
* @see #setContextVersion
* @see javax.media.opengl.GLContext#CTX_OPTION_ANY
* @see javax.media.opengl.GLContext#CTX_PROFILE_COMPAT
* @see javax.media.opengl.GLContext#CTX_IMPL_ES2_COMPAT
*/
- protected final void setGLFunctionAvailability(boolean force, int major, int minor, int ctxProfileBits) {
+ protected final boolean setGLFunctionAvailability(boolean force, int major, int minor, int ctxProfileBits,
+ boolean strictMatch, boolean withinGLVersionsMapping) {
if(null!=this.gl && null!=glProcAddressTable && !force) {
- return; // already done and not forced
+ return true; // already done and not forced
+ }
+
+ if ( 0 < major && !GLContext.isValidGLVersion(ctxProfileBits, major, minor) ) {
+ throw new GLException("Invalid GL Version Request "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
}
if(null==this.gl || !verifyInstance(gl.getGLProfile(), "Impl", this.gl)) {
- setGL(createGL(getGLDrawable().getGLProfile()));
+ setGL( createGL( getGLDrawable().getGLProfile() ) );
}
updateGLXProcAddressTable();
- initGLRendererStrings();
-
- if(!isCurrentContextHardwareRasterizer()) {
- ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT;
- }
final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration();
final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
-
+ final int reqCtxProfileBits = ctxProfileBits;
+ final VersionNumber reqGLVersion = new VersionNumber(major, minor, 0);
+ final VersionNumber hasGLVersionByString;
+ {
+ final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings();
+ if( !initGLRendererAndGLVersionStringsOK ) {
+ final String errMsg = "Intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null);
+ if( strictMatch ) {
+ // query mode .. simply fail
+ if(DEBUG) {
+ System.err.println("Warning: setGLFunctionAvailability: "+errMsg);
+ }
+ return false;
+ } else {
+ // unusable GL context - non query mode - hard fail!
+ throw new GLException(errMsg);
+ }
+ } else {
+ hasGLVersionByString = getGLVersionNumber(ctxProfileBits, glVersion);
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Given "+adevice+
+ " - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)+
+ ", Number(Str) "+hasGLVersionByString);
+ }
+ }
+ }
+
+ final boolean isES = 0 != ( CTX_PROFILE_ES & ctxProfileBits );
+
+ //
+ // Validate GL version either by GL-Integer or GL-String
+ //
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Pre version verification - expected "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+", strictMatch "+strictMatch+", glVersionsMapping " +withinGLVersionsMapping);
+ }
+
+ final boolean versionGL3IntOK;
+ {
+ // Validate the requested version w/ the GL-version from an integer query,
+ // as supported by GL [ES] >= 3.0 implementation.
+ final VersionNumber hasGLVersionByInt;
+ {
+ final int[] glIntMajor = new int[] { 0 }, glIntMinor = new int[] { 0 };
+ final boolean getGLIntVersionOK = getGLIntVersion(glIntMajor, glIntMinor);
+ if( !getGLIntVersionOK ) {
+ final String errMsg = "Fetching GL Integer Version failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null);
+ if( strictMatch ) {
+ // query mode .. simply fail
+ if(DEBUG) {
+ System.err.println("Warning: setGLFunctionAvailability: "+errMsg);
+ }
+ return false;
+ } else {
+ // unusable GL context - non query mode - hard fail!
+ throw new GLException(errMsg);
+ }
+ }
+ hasGLVersionByInt = new VersionNumber(glIntMajor[0], glIntMinor[0], 0);
+ }
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Version verification (Int): String "+glVersion+", Number(Int) "+hasGLVersionByInt);
+ }
+
+ // Only validate integer based version if:
+ // - ctx >= 3.0 is requested _or_ string-version >= 3.0
+ // - _and_ a valid int version was fetched,
+ // otherwise cont. w/ version-string method -> 3.0 > Version || Version > MAX!
+ //
+ if ( ( major >= 3 || hasGLVersionByString.compareTo(Version300) >= 0 ) &&
+ GLContext.isValidGLVersion(ctxProfileBits, hasGLVersionByInt.getMajor(), hasGLVersionByInt.getMinor()) ) {
+ // Strict Match (GLVersionMapping):
+ // Relaxed match for versions ( !isES && major < 3 ) requests, last resort!
+ // Otherwise:
+ // - fail if hasVersion < reqVersion (desktop and ES)
+ // - fail if ES major-version mismatch:
+ // - request 1, >= 3 must be equal
+ // - request 2 must be [2..3]
+ //
+ final int hasMajor = hasGLVersionByInt.getMajor();
+ if( strictMatch &&
+ ( ( ( isES || major >= 3 ) && hasGLVersionByInt.compareTo(reqGLVersion) < 0 ) ||
+ ( isES &&
+ (
+ ( 2 == major && ( 2 > hasMajor || hasMajor > 3 ) ) || // 2 -> [2..3]
+ ( ( 1 == major || 3 <= major ) && major != hasMajor ) // 1,3,.. -> equal
+ )
+ )
+ ) ) {
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (Int): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByInt);
+ }
+ return false;
+ }
+ // Use returned GL version!
+ major = hasGLVersionByInt.getMajor();
+ minor = hasGLVersionByInt.getMinor();
+ versionGL3IntOK = true;
+ } else {
+ versionGL3IntOK = false;
+ }
+ }
+ final boolean versionValidated;
+
+ if( versionGL3IntOK ) {
+ versionValidated = true;
+ } else {
+ // Validate the requested version w/ the GL-version from the version string.
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Version verification (String): String "+glVersion+", Number(Str) "+hasGLVersionByString);
+ }
+
+ // Only validate if a valid string version was fetched -> MIN > Version || Version > MAX!
+ if( null != hasGLVersionByString ) {
+ // Strict Match (GLVersionMapping):
+ // Relaxed match for versions ( !isES && major < 3 ) requests, last resort!
+ // Otherwise:
+ // - fail if hasVersion < reqVersion (desktop and ES)
+ // - fail if ES major-version mismatch:
+ // - request 1, >= 3 must be equal
+ // - request 2 must be [2..3]
+ //
+ final int hasMajor = hasGLVersionByString.getMajor();
+ if( strictMatch &&
+ ( ( ( isES || major >= 3 ) && hasGLVersionByString.compareTo(reqGLVersion) < 0 ) ||
+ ( isES &&
+ (
+ ( 2 == major && ( 2 > hasMajor || hasMajor > 3 ) ) || // 2 -> [2..3]
+ ( ( 1 == major || 3 <= major ) && major != hasMajor ) // 1,3,.. -> equal
+ )
+ )
+ ) ) {
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL version mismatch (String): "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByString);
+ }
+ return false;
+ }
+ if( strictMatch && !versionGL3IntOK && major >= 3 ) {
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL3/ES3 version Int failed, String: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion+", "+hasGLVersionByString);
+ }
+ return false;
+ }
+ // Use returned GL version!
+ major = hasGLVersionByString.getMajor();
+ minor = hasGLVersionByString.getMinor();
+ versionValidated = true;
+ } else {
+ versionValidated = false;
+ }
+ }
+ if( strictMatch && !versionValidated ) {
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, No GL version validation possible: "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)+" -> "+glVersion);
+ }
+ return false;
+ }
+ if (DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Post version verification req "+
+ GLContext.getGLVersion(reqGLVersion.getMajor(), reqGLVersion.getMinor(), reqCtxProfileBits, null)+" -> has "+
+ GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
+ ", strictMatch "+strictMatch+", versionValidated "+versionValidated+", versionGL3IntOK "+versionGL3IntOK);
+ }
+
+ if( major < 2 ) { // there is no ES2/3-compat for a profile w/ major < 2
+ ctxProfileBits &= ~ ( GLContext.CTX_IMPL_ES2_COMPAT | GLContext.CTX_IMPL_ES3_COMPAT ) ;
+ }
+
+ final VersionNumberString vendorVersion = GLVersionNumber.createVendorVersion(glVersion);
+
+ setRendererQuirks(adevice, getDrawableImpl().getFactoryImpl(),
+ reqGLVersion.getMajor(), reqGLVersion.getMinor(), reqCtxProfileBits,
+ major, minor, ctxProfileBits, vendorVersion, withinGLVersionsMapping);
+
+ if( strictMatch && glRendererQuirks.exist(GLRendererQuirks.GLNonCompliant) ) {
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: FAIL, GL is not compliant: "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)+", "+glRenderer);
+ }
+ return false;
+ }
+
+ if(!isCurrentContextHardwareRasterizer()) {
+ ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT;
+ }
+
contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits);
if (DEBUG) {
- System.err.println(getThreadName() + ": Context FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion));
}
//
@@ -1011,7 +1574,7 @@ public abstract class GLContextImpl extends GLContext {
synchronized(mappedContextTypeObjectLock) {
table = mappedGLProcAddress.get( contextFQN );
if(null != table && !verifyInstance(gl.getGLProfile(), "ProcAddressTable", table)) {
- throw new InternalError("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
+ throw new InternalError("GLContext GL ProcAddressTable mapped key("+contextFQN+" - " + GLContext.getGLVersion(major, minor, ctxProfileBits, null)+
") -> "+ table.getClass().getName()+" not matching "+gl.getGLProfile().getGLImplBaseClassName());
}
}
@@ -1021,8 +1584,7 @@ public abstract class GLContextImpl extends GLContext {
System.err.println(getThreadName() + ": GLContext GL ProcAddressTable reusing key("+contextFQN+") -> "+toHexString(table.hashCode()));
}
} else {
- glProcAddressTable = (ProcAddressTable) createInstance(gl.getGLProfile(), "ProcAddressTable",
- new Class[] { FunctionAddressResolver.class } ,
+ glProcAddressTable = (ProcAddressTable) createInstance(gl.getGLProfile(), false,
new Object[] { new GLProcAddressResolver() } );
resetProcAddressTable(getGLProcAddressTable());
synchronized(mappedContextTypeObjectLock) {
@@ -1032,7 +1594,7 @@ public abstract class GLContextImpl extends GLContext {
}
}
}
-
+
//
// Update ExtensionAvailabilityCache
//
@@ -1047,7 +1609,7 @@ public abstract class GLContextImpl extends GLContext {
}
} else {
extensionAvailability = new ExtensionAvailabilityCache();
- setContextVersion(major, minor, ctxProfileBits, false); // pre-set of GL version, required for extension cache usage
+ setContextVersion(major, minor, ctxProfileBits, vendorVersion, false); // pre-set of GL version, required for extension cache usage
extensionAvailability.reset(this);
synchronized(mappedContextTypeObjectLock) {
mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability);
@@ -1055,116 +1617,430 @@ public abstract class GLContextImpl extends GLContext {
System.err.println(getThreadName() + ": GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+toHexString(extensionAvailability.hashCode()) + " - entries: "+extensionAvailability.getTotalExtensionCount());
}
}
- }
- if( isExtensionAvailable("GL_ARB_ES2_compatibility") ) {
+ }
+
+ if( isES ) {
+ if( major >= 3 ) {
+ ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ;
+ ctxProfileBits |= CTX_IMPL_FBO;
+ } else if( major >= 2 ) {
+ ctxProfileBits |= CTX_IMPL_ES2_COMPAT;
+ ctxProfileBits |= CTX_IMPL_FBO;
+ }
+ } else if( ( major > 4 || major == 4 && minor >= 3 ) ||
+ ( ( major > 3 || major == 3 && minor >= 1 ) && isExtensionAvailable( GLExtensions.ARB_ES3_compatibility ) ) ) {
+ // See GLContext.isGLES3CompatibleAvailable(..)/isGLES3Compatible()
+ // Includes [ GL &ge; 4.3, GL &ge; 3.1 w/ GL_ARB_ES3_compatibility and GLES3 ]
+ ctxProfileBits |= CTX_IMPL_ES3_COMPAT | CTX_IMPL_ES2_COMPAT ;
+ ctxProfileBits |= CTX_IMPL_FBO;
+ } else if( isExtensionAvailable( GLExtensions.ARB_ES2_compatibility ) ) {
ctxProfileBits |= CTX_IMPL_ES2_COMPAT;
+ ctxProfileBits |= CTX_IMPL_FBO;
+ } else if( hasFBOImpl(major, ctxProfileBits, extensionAvailability) ) {
+ ctxProfileBits |= CTX_IMPL_FBO;
}
-
+
+ if( ( isES && major == 1 ) || isExtensionAvailable(GLExtensions.OES_single_precision) ) {
+ ctxProfileBits |= CTX_IMPL_FP32_COMPAT_API;
+ }
+
+ if(FORCE_NO_FBO_SUPPORT) {
+ ctxProfileBits &= ~CTX_IMPL_FBO ;
+ }
+
//
// Set GL Version (complete w/ version string)
//
- setContextVersion(major, minor, ctxProfileBits, true);
-
+ setContextVersion(major, minor, ctxProfileBits, vendorVersion, true);
+
+ finalizeInit(gl);
+
setDefaultSwapInterval();
+
+ final int glErrX = gl.glGetError(); // clear GL error, maybe caused by above operations
+
+ if(DEBUG) {
+ System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.X: OK "+contextFQN+" - "+GLContext.getGLVersion(ctxVersion.getMajor(), ctxVersion.getMinor(), ctxOptions, null)+" - glErr "+toHexString(glErrX));
+ }
+ return true;
}
- protected final void removeCachedVersion(int major, int minor, int ctxProfileBits) {
+ private final void setRendererQuirks(final AbstractGraphicsDevice adevice, final GLDrawableFactoryImpl factory,
+ int reqMajor, int reqMinor, int reqCTP,
+ int major, int minor, int ctp, final VersionNumberString vendorVersion,
+ boolean withinGLVersionsMapping) {
+ int[] quirks = new int[GLRendererQuirks.COUNT + 1]; // + 1 ( NoFullFBOSupport )
+ int i = 0;
+
+ final String MesaSP = "Mesa ";
+ // final String MesaRendererAMDsp = " AMD ";
+ final String MesaRendererIntelsp = "Intel(R)";
+ final boolean hwAccel = 0 == ( ctp & GLContext.CTX_IMPL_ACCEL_SOFT );
+ final boolean compatCtx = 0 != ( ctp & GLContext.CTX_PROFILE_COMPAT );
+ final boolean esCtx = 0 != ( ctp & GLContext.CTX_PROFILE_ES );
+ final boolean isX11 = NativeWindowFactory.TYPE_X11 == NativeWindowFactory.getNativeWindowType(true);
+ final boolean isWindows = Platform.getOSType() == Platform.OSType.WINDOWS;
+ final boolean isDriverMesa = glRenderer.contains(MesaSP) || glRenderer.contains("Gallium ");
+ final boolean isDriverATICatalyst = !isDriverMesa && ( glVendor.contains("ATI Technologies") || glRenderer.startsWith("ATI ") );
+ final boolean isDriverNVIDIAGeForce = !isDriverMesa && ( glVendor.contains("NVIDIA Corporation") || glRenderer.contains("NVIDIA ") );
+
+ //
+ // General Quirks
+ //
+ if( esCtx ) {
+ if( 2 == reqMajor && 2 < major ) {
+ final int quirk = GLRendererQuirks.GLES3ViaEGLES2Config;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: ES req "+reqMajor+" and 2 < "+major);
+ }
+ quirks[i++] = quirk;
+ if( withinGLVersionsMapping ) {
+ // Thread safe due to single threaded initialization!
+ GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1);
+ } else {
+ // FIXME: Remove when moving EGL/ES to ARB ctx creation
+ synchronized(GLContextImpl.class) {
+ GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1);
+ }
+ }
+ }
+ }
+
+ //
+ // OS related quirks
+ //
+ if( Platform.getOSType() == Platform.OSType.MACOS ) {
+ //
+ // OSX
+ //
+ {
+ final int quirk = GLRendererQuirks.NoOffscreenBitmap;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType());
+ }
+ quirks[i++] = quirk;
+ }
+ if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Mavericks) >= 0 && 3==reqMajor && 4==major ) {
+ final int quirk = GLRendererQuirks.GL4NeedsGL3Request;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", req "+reqMajor+"."+reqMinor);
+ }
+ quirks[i++] = quirk;
+ if( withinGLVersionsMapping ) {
+ // Thread safe due to single threaded initialization!
+ GLRendererQuirks.addStickyDeviceQuirks(adevice, quirks, i-1, 1);
+ }
+ }
+ if( isDriverNVIDIAGeForce ) {
+ final VersionNumber osxVersionNVFlushClean = new VersionNumber(10,7,3); // < OSX 10.7.3 w/ NV needs glFlush
+ if( Platform.getOSVersionNumber().compareTo(osxVersionNVFlushClean) < 0 ) {
+ final int quirk = GLRendererQuirks.GLFlushBeforeRelease;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ if( Platform.getOSVersionNumber().compareTo(Platform.OSXVersion.Lion) < 0 ) { // < OSX 10.7.0 w/ NV has unstable GLSL
+ final int quirk = GLRendererQuirks.GLSLNonCompliant;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", OS Version "+Platform.getOSVersionNumber()+", Renderer "+glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ }
+ } else if( isWindows ) {
+ //
+ // WINDOWS
+ //
+ {
+ final int quirk = GLRendererQuirks.NoDoubleBufferedBitmap;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType());
+ }
+ quirks[i++] = quirk;
+ }
+
+ if( isDriverATICatalyst ) {
+ final VersionNumber winXPVersionNumber = new VersionNumber ( 5, 1, 0);
+ final VersionNumber amdSafeMobilityVersion = new VersionNumber(12, 102, 3);
+
+ if ( vendorVersion.compareTo(amdSafeMobilityVersion) < 0 ) { // includes: vendorVersion.isZero()
+ final int quirk = GLRendererQuirks.NeedCurrCtx4ARBCreateContext;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType()+", [Vendor "+glVendor+" or Renderer "+glRenderer+"], driverVersion "+vendorVersion);
+ }
+ quirks[i++] = quirk;
+ }
+
+ if( Platform.getOSVersionNumber().compareTo(winXPVersionNumber) <= 0 ) {
+ final int quirk = GLRendererQuirks.NeedCurrCtx4ARBPixFmtQueries;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS-Version "+Platform.getOSType()+" "+Platform.getOSVersionNumber()+", [Vendor "+glVendor+" or Renderer "+glRenderer+"]");
+ }
+ quirks[i++] = quirk;
+ }
+ }
+ } else if( Platform.OSType.ANDROID == Platform.getOSType() ) {
+ //
+ // ANDROID
+ //
+ // Renderer related quirks, may also involve OS
+ if( glRenderer.contains("PowerVR") ) {
+ final int quirk = GLRendererQuirks.NoSetSwapInterval;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ if( glRenderer.contains("Immersion.16") ) {
+ final int quirk = GLRendererQuirks.GLSharedContextBuggy;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + ", Renderer " + glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ }
+
+ //
+ // Windowing Toolkit related quirks
+ //
+ if( isX11 ) {
+ //
+ // X11
+ //
+ {
+ //
+ // Quirk: DontCloseX11Display
+ //
+ final int quirk = GLRendererQuirks.DontCloseX11Display;
+ if( glRenderer.contains(MesaSP) ) {
+ if ( glRenderer.contains("X11") && vendorVersion.compareTo(Version800) < 0 ) {
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer + ", Version=[vendor " + vendorVersion + ", GL " + glVersion+"]");
+ }
+ quirks[i++] = quirk;
+ }
+ } else if( isDriverATICatalyst ) {
+ {
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 Renderer=" + glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ } else if( jogamp.nativewindow.x11.X11Util.getMarkAllDisplaysUnclosable() ) {
+ {
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11Util Downstream");
+ }
+ quirks[i++] = quirk;
+ }
+ }
+ }
+ }
+
+
+ //
+ // RENDERER related quirks
+ //
+ if( isDriverMesa ) {
+ final VersionNumber mesaIntelBuggySharedCtx921 = new VersionNumber(9, 2, 1);
+
+ {
+ final int quirk = GLRendererQuirks.NoSetSwapIntervalPostRetarget;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ if( hwAccel /* glRenderer.contains( MesaRendererIntelsp ) || glRenderer.contains( MesaRendererAMDsp ) */ )
+ {
+ final int quirk = GLRendererQuirks.NoDoubleBufferedPBuffer;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ if (compatCtx && (major > 3 || (major == 3 && minor >= 1))) {
+ // FIXME: Apply vendor version constraints!
+ final int quirk = GLRendererQuirks.GLNonCompliant;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: Renderer " + glRenderer);
+ }
+ quirks[i++] = quirk;
+ }
+ if( glRenderer.contains( MesaRendererIntelsp ) &&
+ vendorVersion.compareTo(mesaIntelBuggySharedCtx921) >= 0 && isX11 ) {
+ final int quirk = GLRendererQuirks.GLSharedContextBuggy;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: X11 / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion);
+ }
+ quirks[i++] = quirk;
+ }
+ if( isWindows && glRenderer.contains("SVGA3D") ) {
+ final VersionNumber mesaSafeFBOVersion = new VersionNumber(8, 0, 0);
+ if ( vendorVersion.compareTo(mesaSafeFBOVersion) < 0 ) { // includes: vendorVersion.isZero()
+ final int quirk = GLRendererQuirks.NoFullFBOSupport;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: OS "+Platform.getOSType() + " / Renderer " + glRenderer + " / Mesa-Version "+vendorVersion);
+ }
+ quirks[i++] = quirk;
+ }
+ }
+ }
+
+ //
+ // Property related quirks
+ //
+ if( FORCE_MIN_FBO_SUPPORT ) {
+ final int quirk = GLRendererQuirks.NoFullFBOSupport;
+ if(DEBUG) {
+ System.err.println("Quirk: "+GLRendererQuirks.toString(quirk)+": cause: property");
+ }
+ quirks[i++] = quirk;
+ }
+
+ glRendererQuirks = new GLRendererQuirks(quirks, 0, i);
+ if(DEBUG) {
+ System.err.println("Quirks local.0: "+glRendererQuirks);
+ }
+ {
+ // Merge sticky quirks, thread safe due to single threaded initialization!
+ GLRendererQuirks.pushStickyDeviceQuirks(adevice, glRendererQuirks);
+
+ final AbstractGraphicsDevice factoryDefaultDevice = factory.getDefaultDevice();
+ if( !GLRendererQuirks.areSameStickyDevice(factoryDefaultDevice, adevice) ) {
+ GLRendererQuirks.pushStickyDeviceQuirks(factoryDefaultDevice, glRendererQuirks);
+ }
+ if( esCtx ) {
+ final AbstractGraphicsDevice eglFactoryDefaultDevice = GLDrawableFactory.getEGLFactory().getDefaultDevice();
+ if( !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, adevice) &&
+ !GLRendererQuirks.areSameStickyDevice(eglFactoryDefaultDevice, factoryDefaultDevice) ) {
+ GLRendererQuirks.pushStickyDeviceQuirks(eglFactoryDefaultDevice, glRendererQuirks);
+ }
+ }
+ }
+ if(DEBUG) {
+ System.err.println("Quirks local.X: "+glRendererQuirks);
+ System.err.println("Quirks sticky on "+adevice+": "+GLRendererQuirks.getStickyDeviceQuirks(adevice));
+ }
+ }
+
+ private static final boolean hasFBOImpl(int major, int ctp, ExtensionAvailabilityCache extCache) {
+ return ( 0 != (ctp & CTX_PROFILE_ES) && major >= 2 ) || // ES >= 2.0
+
+ major >= 3 || // any >= 3.0 GL ctx (core, compat and ES)
+
+ ( null != extCache &&
+
+ extCache.isExtensionAvailable(GLExtensions.ARB_ES2_compatibility) || // ES 2.0 compatible
+
+ extCache.isExtensionAvailable(GLExtensions.ARB_framebuffer_object) || // ARB_framebuffer_object
+
+ extCache.isExtensionAvailable(GLExtensions.EXT_framebuffer_object) || // EXT_framebuffer_object
+
+ extCache.isExtensionAvailable(GLExtensions.OES_framebuffer_object) ) ; // OES_framebuffer_object excluded
+ }
+
+ private final void removeCachedVersion(int major, int minor, int ctxProfileBits) {
if(!isCurrentContextHardwareRasterizer()) {
ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT;
}
final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration();
final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice();
-
+
contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits);
if (DEBUG) {
System.err.println(getThreadName() + ": RM Context FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null));
}
synchronized(mappedContextTypeObjectLock) {
- ProcAddressTable table = mappedGLProcAddress.remove( contextFQN );
+ final ProcAddressTable table = mappedGLProcAddress.remove( contextFQN );
if(DEBUG) {
- System.err.println(getThreadName() + ": RM GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+table.hashCode());
+ final int hc = null != table ? table.hashCode() : 0;
+ System.err.println(getThreadName() + ": RM GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+toHexString(hc));
}
}
synchronized(mappedContextTypeObjectLock) {
- ExtensionAvailabilityCache eCache = mappedExtensionAvailabilityCache.remove( contextFQN );
+ final ExtensionAvailabilityCache eCache = mappedExtensionAvailabilityCache.remove( contextFQN );
if(DEBUG) {
- System.err.println(getThreadName() + ": RM GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+eCache.hashCode());
+ final int hc = null != eCache ? eCache.hashCode() : 0;
+ System.err.println(getThreadName() + ": RM GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+toHexString(hc));
}
}
}
private final boolean isCurrentContextHardwareRasterizer() {
boolean isHardwareRasterizer = true;
-
+
if(!drawable.getChosenGLCapabilities().getHardwareAccelerated()) {
isHardwareRasterizer = false;
} else {
- isHardwareRasterizer = ! ( glRendererLowerCase.contains("software") /* Mesa3D */ ||
- glRendererLowerCase.contains("mesa x11") /* Mesa3D*/ ||
+ isHardwareRasterizer = ! ( glRendererLowerCase.contains("software") /* Mesa3D, Apple */ ||
+ glRendererLowerCase.contains("mesa x11") /* Mesa3D */ ||
glRendererLowerCase.contains("softpipe") /* Gallium */ ||
- glRendererLowerCase.contains("llvmpipe") /* Gallium */
+ glRendererLowerCase.contains("llvmpipe") /* Gallium */
);
}
return isHardwareRasterizer;
}
-
+
/**
* Updates the platform's 'GLX' function cache
*/
protected abstract void updateGLXProcAddressTable();
protected abstract StringBuilder getPlatformExtensionsStringImpl();
-
+
+ @Override
public final boolean isFunctionAvailable(String glFunctionName) {
// Check GL 1st (cached)
if(null!=glProcAddressTable) { // null if this context wasn't not created
try {
- if(0!=glProcAddressTable.getAddressFor(glFunctionName)) {
+ if( glProcAddressTable.isFunctionAvailable( glFunctionName ) ) {
return true;
}
} catch (Exception e) {}
}
// Check platform extensions 2nd (cached) - context had to be enabled once
- final ProcAddressTable pTable = getPlatformExtProcAddressTable();
- if(null!=pTable) {
+ final ProcAddressTable pTable = getPlatformExtProcAddressTable();
+ if(null!=pTable) {
try {
- if(0!=pTable.getAddressFor(glFunctionName)) {
+ if( pTable.isFunctionAvailable( glFunctionName ) ) {
return true;
}
} catch (Exception e) {}
}
// dynamic function lookup at last incl name aliasing (not cached)
- DynamicLookupHelper dynLookup = getDrawableImpl().getGLDynamicLookupHelper();
- String tmpBase = GLExtensionNames.normalizeVEN(GLExtensionNames.normalizeARB(glFunctionName, true), true);
- long addr = 0;
- int variants = GLExtensionNames.getFuncNamePermutationNumber(tmpBase);
- for(int i = 0; 0==addr && i < variants; i++) {
- String tmp = GLExtensionNames.getFuncNamePermutation(tmpBase, i);
+ final DynamicLookupHelper dynLookup = getDrawableImpl().getGLDynamicLookupHelper();
+ final String tmpBase = GLNameResolver.normalizeVEN(GLNameResolver.normalizeARB(glFunctionName, true), true);
+ boolean res = false;
+ int variants = GLNameResolver.getFuncNamePermutationNumber(tmpBase);
+ for(int i = 0; !res && i < variants; i++) {
+ final String tmp = GLNameResolver.getFuncNamePermutation(tmpBase, i);
try {
- addr = dynLookup.dynamicLookupFunction(tmp);
+ res = dynLookup.isFunctionAvailable(tmp);
} catch (Exception e) { }
}
- if(0!=addr) {
- return true;
- }
- return false;
+ return res;
}
- public boolean isExtensionAvailable(String glExtensionName) {
+ @Override
+ public final boolean isExtensionAvailable(String glExtensionName) {
if(null!=extensionAvailability) {
return extensionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName));
}
return false;
}
+ @Override
public final int getPlatformExtensionCount() {
return null != extensionAvailability ? extensionAvailability.getPlatformExtensionCount() : 0;
}
-
+
+ @Override
public final String getPlatformExtensionsString() {
if(null!=extensionAvailability) {
return extensionAvailability.getPlatformExtensionsString();
@@ -1172,10 +2048,12 @@ public abstract class GLContextImpl extends GLContext {
return null;
}
+ @Override
public final int getGLExtensionCount() {
return null != extensionAvailability ? extensionAvailability.getGLExtensionCount() : 0;
}
-
+
+ @Override
public final String getGLExtensionsString() {
if(null!=extensionAvailability) {
return extensionAvailability.getGLExtensionsString();
@@ -1189,15 +2067,15 @@ public abstract class GLContextImpl extends GLContext {
}
return false;
}
-
+
protected static String getContextFQN(AbstractGraphicsDevice device, int major, int minor, int ctxProfileBits) {
// remove non-key values
- ctxProfileBits &= ~( GLContext.CTX_OPTION_DEBUG | GLContext.CTX_IMPL_ES2_COMPAT ) ;
-
+ ctxProfileBits &= CTX_IMPL_CACHE_MASK;
+
return device.getUniqueID() + "-" + toHexString(composeBits(major, minor, ctxProfileBits));
}
- protected String getContextFQN() {
+ protected final String getContextFQN() {
return contextFQN;
}
@@ -1208,32 +2086,63 @@ public abstract class GLContextImpl extends GLContext {
throw new GLException("Not supported on non-pbuffer contexts");
}
- /** On some platforms the mismatch between OpenGL's coordinate
- system (origin at bottom left) and the window system's
- coordinate system (origin at top left) necessitates a vertical
- flip of pixels read from offscreen contexts. */
- public abstract boolean offscreenImageNeedsVerticalFlip();
+ @Override
+ public int getDefaultPixelDataType() {
+ evalPixelDataType();
+ return pixelDataType;
+ }
- /** Only called for offscreen contexts; needed by glReadPixels */
- public abstract int getOffscreenContextPixelDataType();
+ @Override
+ public int getDefaultPixelDataFormat() {
+ evalPixelDataType();
+ return pixelDataFormat;
+ }
+ private final void evalPixelDataType() {
+ if(!pixelDataEvaluated) {
+ synchronized(this) {
+ if(!pixelDataEvaluated) {
+ boolean ok = false;
+ /* if(isGL2GL3() && 3 == components) {
+ pixelDataInternalFormat=GL.GL_RGB;
+ pixelDataFormat=GL.GL_RGB;
+ pixelDataType = GL.GL_UNSIGNED_BYTE;
+ ok = true;
+ } else */ if( isGLES2Compatible() || isExtensionAvailable(GLExtensions.OES_read_format) ) {
+ final int[] glImplColorReadVals = new int[] { 0, 0 };
+ gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_FORMAT, glImplColorReadVals, 0);
+ gl.glGetIntegerv(GL.GL_IMPLEMENTATION_COLOR_READ_TYPE, glImplColorReadVals, 1);
+ // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB;
+ pixelDataFormat = glImplColorReadVals[0];
+ pixelDataType = glImplColorReadVals[1];
+ ok = 0 != pixelDataFormat && 0 != pixelDataType;
+ }
+ if( !ok ) {
+ // RGBA read is safe for all GL profiles
+ // pixelDataInternalFormat = (4 == components) ? GL.GL_RGBA : GL.GL_RGB;
+ pixelDataFormat=GL.GL_RGBA;
+ pixelDataType = GL.GL_UNSIGNED_BYTE;
+ }
+ // TODO: Consider:
+ // return gl.isGL2GL3()?GL2GL3.GL_UNSIGNED_INT_8_8_8_8_REV:GL.GL_UNSIGNED_SHORT_5_5_5_1;
+ pixelDataEvaluated = true;
+ }
+ }
+ }
+ }
//----------------------------------------------------------------------
// Helpers for buffer object optimizations
-
- public void setBufferSizeTracker(GLBufferSizeTracker bufferSizeTracker) {
- this.bufferSizeTracker = bufferSizeTracker;
- }
- public GLBufferSizeTracker getBufferSizeTracker() {
- return bufferSizeTracker;
+ public final GLBufferObjectTracker getBufferObjectTracker() {
+ return bufferObjectTracker;
}
- public GLBufferStateTracker getBufferStateTracker() {
+ public final GLBufferStateTracker getBufferStateTracker() {
return bufferStateTracker;
}
- public GLStateTracker getGLStateTracker() {
+ public final GLStateTracker getGLStateTracker() {
return glStateTracker;
}
@@ -1242,38 +2151,123 @@ public abstract class GLContextImpl extends GLContext {
// current on the OpenGL worker thread
//
- public boolean hasWaiters() {
+ /**
+ * Returns true if the given thread is owner, otherwise false.
+ * <p>
+ * Method exists merely for code validation of {@link #isCurrent()}.
+ * </p>
+ */
+ public final boolean isOwner(Thread thread) {
+ return lock.isOwner(thread);
+ }
+
+ /**
+ * Returns true if there are other threads waiting for this GLContext to {@link #makeCurrent()}, otherwise false.
+ * <p>
+ * Since method does not perform any synchronization, accurate result are returned if lock is hold - only.
+ * </p>
+ */
+ public final boolean hasWaiters() {
return lock.getQueueLength()>0;
}
-
+
+ /**
+ * Returns the number of hold locks. See {@link RecursiveLock#getHoldCount()} for semantics.
+ * <p>
+ * Since method does not perform any synchronization, accurate result are returned if lock is hold - only.
+ * </p>
+ */
+ public final int getLockCount() {
+ return lock.getHoldCount();
+ }
+
+ //---------------------------------------------------------------------------
+ // Special FBO hook
+ //
+
+ /**
+ * Tracks {@link GL#GL_FRAMEBUFFER}, {@link GL2GL3#GL_DRAW_FRAMEBUFFER} and {@link GL2GL3#GL_READ_FRAMEBUFFER}
+ * to be returned via {@link #getBoundFramebuffer(int)}.
+ *
+ * <p>Invoked by {@link GL#glBindFramebuffer(int, int)}. </p>
+ *
+ * <p>Assumes valid <code>framebufferName</code> range of [0..{@link Integer#MAX_VALUE}]</p>
+ *
+ * <p>Does not throw an exception if <code>target</code> is unknown or <code>framebufferName</code> invalid.</p>
+ */
+ public final void setBoundFramebuffer(int target, int framebufferName) {
+ if(0 > framebufferName) {
+ return; // ignore invalid name
+ }
+ switch(target) {
+ case GL.GL_FRAMEBUFFER:
+ boundFBOTarget[0] = framebufferName; // draw
+ boundFBOTarget[1] = framebufferName; // read
+ break;
+ case GL2GL3.GL_DRAW_FRAMEBUFFER:
+ boundFBOTarget[0] = framebufferName; // draw
+ break;
+ case GL2GL3.GL_READ_FRAMEBUFFER:
+ boundFBOTarget[1] = framebufferName; // read
+ break;
+ default: // ignore untracked target
+ }
+ }
+ @Override
+ public final int getBoundFramebuffer(int target) {
+ switch(target) {
+ case GL.GL_FRAMEBUFFER:
+ case GL2GL3.GL_DRAW_FRAMEBUFFER:
+ return boundFBOTarget[0]; // draw
+ case GL2GL3.GL_READ_FRAMEBUFFER:
+ return boundFBOTarget[1]; // read
+ default:
+ throw new InternalError("Invalid FBO target name: "+toHexString(target));
+ }
+ }
+
+ @Override
+ public final int getDefaultDrawFramebuffer() { return drawable.getDefaultDrawFramebuffer(); }
+ @Override
+ public final int getDefaultReadFramebuffer() { return drawable.getDefaultReadFramebuffer(); }
+ @Override
+ public final int getDefaultReadBuffer() { return drawable.getDefaultReadBuffer(gl, drawableRead != drawable); }
+
//---------------------------------------------------------------------------
// GL_ARB_debug_output, GL_AMD_debug_output helpers
//
+ @Override
public final String getGLDebugMessageExtension() {
return glDebugHandler.getExtension();
}
+ @Override
public final boolean isGLDebugMessageEnabled() {
return glDebugHandler.isEnabled();
}
-
+
+ @Override
public final int getContextCreationFlags() {
- return additionalCtxCreationFlags;
+ return additionalCtxCreationFlags;
}
+ @Override
public final void setContextCreationFlags(int flags) {
if(!isCreated()) {
additionalCtxCreationFlags = flags & GLContext.CTX_OPTION_DEBUG;
}
}
-
- public final boolean isGLDebugSynchronous() { return glDebugHandler.isSynchronous(); }
-
+
+ @Override
+ public final boolean isGLDebugSynchronous() { return glDebugHandler.isSynchronous(); }
+
+ @Override
public final void setGLDebugSynchronous(boolean synchronous) {
glDebugHandler.setSynchronous(synchronous);
}
-
+
+ @Override
public final void enableGLDebugMessage(boolean enable) throws GLException {
if(!isCreated()) {
if(enable) {
@@ -1286,40 +2280,48 @@ public abstract class GLContextImpl extends GLContext {
glDebugHandler.enable(enable);
}
}
-
- public final void addGLDebugListener(GLDebugListener listener) {
+
+ @Override
+ public final void addGLDebugListener(GLDebugListener listener) {
glDebugHandler.addListener(listener);
}
-
+
+ @Override
public final void removeGLDebugListener(GLDebugListener listener) {
glDebugHandler.removeListener(listener);
- }
-
+ }
+
+ @Override
public final 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);
+ gl.getGL2GL3().glDebugMessageControl(source, type, severity, count, ids, enabled);
} else if(glDebugHandler.isExtensionAMD()) {
gl.getGL2GL3().glDebugMessageEnableAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, count, ids, enabled);
- }
+ }
}
-
+
+ @Override
public final 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);
+ gl.getGL2GL3().glDebugMessageControl(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);
}
}
-
+
+ @Override
public final void glDebugMessageInsert(int source, int type, int id, int severity, String buf) {
final int len = (null != buf) ? buf.length() : 0;
if(glDebugHandler.isExtensionARB()) {
- gl.getGL2GL3().glDebugMessageInsertARB(source, type, id, severity, len, buf);
+ gl.getGL2GL3().glDebugMessageInsert(source, type, id, severity, len, buf);
} else if(glDebugHandler.isExtensionAMD()) {
gl.getGL2GL3().glDebugMessageInsertAMD(GLDebugMessage.translateARB2AMDCategory(source, type), severity, id, len, buf);
- }
+ }
}
-
+
/** Internal bootstraping glGetString(GL_RENDERER) */
- protected static native String glGetStringInt(int name, long procAddress);
+ private static native String glGetStringInt(int name, long procAddress);
+
+ /** Internal bootstraping glGetIntegerv(..) for version */
+ private static native void glGetIntegervInt(int pname, int[] params, int params_offset, long procAddress);
}