/*
* Copyright (c) 2003 Sun Microsystems, Inc. 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
* PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN
* MICROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL NOT BE LIABLE FOR
* ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR
* DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR
* ITS LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR
* DIRECT, INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE
* 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.
*/
package javax.media.opengl;
import com.jogamp.common.util.*;
import com.jogamp.opengl.impl.DRIHack;
import com.jogamp.opengl.impl.Debug;
import com.jogamp.opengl.impl.GLJNILibLoader;
import com.jogamp.common.jvm.JVMUtil;
import java.util.HashMap;
import java.util.Iterator;
import java.security.*;
import javax.media.opengl.fixedfunc.GLPointerFunc;
import javax.media.nativewindow.NativeWindowFactory;
/**
* Specifies the the OpenGL profile.
*
* This class static singleton initialization queries the availability of all OpenGL Profiles
* and instantiates singleton GLProfile objects for each available profile.
*
* The platform default profile may be used, using {@link GLProfile#GetProfileDefault()},
* or more specialized versions using the other static GetProfile methods.
*/
public class GLProfile implements Cloneable {
public static final boolean DEBUG = Debug.debug("GLProfile");
//
// Query platform available OpenGL implementation
//
public static final boolean isGL4bcAvailable() { return null != mappedProfiles.get(GL4bc); }
public static final boolean isGL4Available() { return null != mappedProfiles.get(GL4); }
public static final boolean isGL3bcAvailable() { return null != mappedProfiles.get(GL3bc); }
public static final boolean isGL3Available() { return null != mappedProfiles.get(GL3); }
public static final boolean isGL2Available() { return null != mappedProfiles.get(GL2); }
public static final boolean isGLES2Available() { return null != mappedProfiles.get(GLES2); }
public static final boolean isGLES1Available() { return null != mappedProfiles.get(GLES1); }
public static final boolean isGL2ES1Available() { return null != mappedProfiles.get(GL2ES1); }
public static final boolean isGL2ES2Available() { return null != mappedProfiles.get(GL2ES2); }
private static final void glAvailabilityToString(StringBuffer sb, int major, int profile) {
String str = GLContext.getGLVersionAvailable(major, profile);
if(null==str) {
throw new GLException("Internal Error");
}
sb.append("[");
sb.append(str);
sb.append("]");
}
public static final String glAvailabilityToString() {
boolean avail;
String str;
StringBuffer sb = new StringBuffer();
sb.append("GLAvailability[Native[GL4bc ");
avail=isGL4bcAvailable();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 4, GLContext.CTX_PROFILE_COMPAT);
}
sb.append(", GL4 ");
avail=isGL4Available();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 4, GLContext.CTX_PROFILE_CORE);
}
sb.append(", GL3bc ");
avail=isGL3bcAvailable();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 3, GLContext.CTX_PROFILE_COMPAT);
}
sb.append(", GL3 ");
avail=isGL3Available();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 3, GLContext.CTX_PROFILE_CORE);
}
sb.append(", GL2 ");
avail=isGL2Available();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 2, GLContext.CTX_PROFILE_COMPAT);
}
sb.append(", GL2ES1 ");
sb.append(isGL2ES1Available());
sb.append(", GLES1 ");
avail=isGLES1Available();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 1, GLContext.CTX_PROFILE_ES);
}
sb.append(", GL2ES2 ");
sb.append(isGL2ES2Available());
sb.append(", GLES2 ");
avail=isGLES2Available();
sb.append(avail);
if(avail) {
glAvailabilityToString(sb, 2, GLContext.CTX_PROFILE_ES);
}
sb.append("], Profiles[");
for(Iterator i=mappedProfiles.values().iterator(); i.hasNext(); ) {
sb.append(((GLProfile)i.next()).toString());
sb.append(", ");
}
sb.append(", default ");
sb.append(defaultGLProfile);
sb.append("]]");
return sb.toString();
}
//
// Public (user-visible) profiles
//
/** The desktop OpenGL compatibility profile 4.x, with x >= 0, ie GL2 plus GL4.
bc
stands for backward compatibility. */
public static final String GL4bc = "GL4bc";
/** The desktop OpenGL core profile 4.x, with x >= 0 */
public static final String GL4 = "GL4";
/** The desktop OpenGL compatibility profile 3.x, with x >= 1, ie GL2 plus GL3.
bc
stands for backward compatibility. */
public static final String GL3bc = "GL3bc";
/** The desktop OpenGL core profile 3.x, with x >= 1 */
public static final String GL3 = "GL3";
/** The desktop OpenGL profile 1.x up to 3.0 */
public static final String GL2 = "GL2";
/** The embedded OpenGL profile ES 1.x, with x >= 0 */
public static final String GLES1 = "GLES1";
/** The embedded OpenGL profile ES 2.x, with x >= 0 */
public static final String GLES2 = "GLES2";
/** The intersection of the desktop GL2 and embedded ES1 profile */
public static final String GL2ES1 = "GL2ES1";
/** The intersection of the desktop GL3, GL2 and embedded ES2 profile */
public static final String GL2ES2 = "GL2ES2";
/** The intersection of the desktop GL3 and GL2 profile */
public static final String GL2GL3 = "GL2GL3";
/**
* All GL Profiles in the order of default detection.
* Desktop compatibility profiles (the one with fixed function pipeline) comes first.
*
* FIXME GL3GL4: Due to GL3 and GL4 implementation bugs, we still choose GL2 first, if available!
*
*
* - GL2
*
- GL3bc
*
- GL4bc
*
- GL2GL3
*
- GL3
*
- GL4
*
- GL2ES2
*
- GLES2
*
- GL2ES1
*
- GLES1
*
*
*/
public static final String[] GL_PROFILE_LIST_ALL = new String[] { GL2, GL3bc, GL4bc, GL2GL3, GL3, GL4, GL2ES2, GLES2, GL2ES1, GLES1 };
/**
* Order of maximum fixed function profiles
*
*
* - GL4bc
*
- GL3bc
*
- GL2
*
- GL2ES1
*
- GLES1
*
*
*/
public static final String[] GL_PROFILE_LIST_MAX_FIXEDFUNC = new String[] { GL4bc, GL3bc, GL2, GL2ES1, GLES1 };
/**
* Order of maximum programmable shader profiles
*
*
* - GL4
*
- GL4bc
*
- GL3
*
- GL3bc
*
- GL2
*
- GL2ES2
*
- GLES2
*
*
*/
public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4, GL4bc, GL3, GL3bc, GL2, GL2ES2, GLES2 };
/**
* All GL2ES2 Profiles in the order of default detection.
*
* FIXME GL3GL4: Due to GL3 and GL4 implementation bugs, we still choose GL2 first, if available!
*
*
* - GL2ES2
*
- GL2
*
- GL3
*
- GL4
*
- GLES2
*
*
*/
public static final String[] GL_PROFILE_LIST_GL2ES2 = new String[] { GL2ES2, GL2, GL3, GL4, GLES2 };
/**
* All GL2ES1 Profiles in the order of default detection.
*
* FIXME GL3GL4: Due to GL3 and GL4 implementation bugs, we still choose GL2 first, if available!
*
*
* - GL2ES1
*
- GL2
*
- GL3bc
*
- GL4bc
*
- GLES1
*
*
*/
public static final String[] GL_PROFILE_LIST_GL2ES1 = new String[] { GL2ES1, GL2, GL3bc, GL4bc, GLES1 };
/** Returns a default GLProfile object, reflecting the best for the running platform.
* It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL}
* @see #GL_PROFILE_LIST_ALL
*/
public static final GLProfile getDefault() {
if(null==defaultGLProfile) {
throw new GLException("No default profile available"); // should never be reached
}
return defaultGLProfile;
}
/**
* Returns the highest profile, implementing the fixed function pipeline
* It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_FIXEDFUNC}
*
* @throws GLException if no implementation for the given profile is found.
* @see #GL_PROFILE_LIST_MAX_FIXEDFUNC
*/
public static final GLProfile getMaxFixedFunc()
throws GLException
{
return get(GL_PROFILE_LIST_MAX_FIXEDFUNC);
}
/**
* Returns the highest profile, implementing the programmable shader pipeline.
* It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER}
*
* @throws GLException if no implementation for the given profile is found.
* @see #GL_PROFILE_LIST_MAX_PROGSHADER
*/
public static final GLProfile getMaxProgrammable()
throws GLException
{
return get(GL_PROFILE_LIST_MAX_PROGSHADER);
}
/**
* Returns a profile, implementing the interface GL2ES1.
* It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_GL2ES1}
*
* @throws GLException if no implementation for the given profile is found.
* @see #GL_PROFILE_LIST_GL2ES1
*/
public static final GLProfile getGL2ES1()
throws GLException
{
return get(GL_PROFILE_LIST_GL2ES1);
}
/**
* Returns a profile, implementing the interface GL2ES2.
* It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_GL2ES2}
*
* @throws GLException if no implementation for the given profile is found.
* @see #GL_PROFILE_LIST_GL2ES2
*/
public static final GLProfile getGL2ES2()
throws GLException
{
return get(GL_PROFILE_LIST_GL2ES2);
}
/** Returns a GLProfile object.
* Verfifies the given profile and chooses an apropriate implementation.
* A generic value of null
or GL
will result in
* the default profile.
*
* @throws GLException if no implementation for the given profile is found.
*/
public static final GLProfile get(String profile)
throws GLException
{
if(null==profile || profile.equals("GL")) return getDefault();
GLProfile glProfile = (GLProfile) mappedProfiles.get(profile);
if(null==glProfile) {
throw new GLException("No implementation for profile "+profile+" available");
}
return glProfile;
}
/**
* Returns the first profile from the given list,
* where an implementation is available.
*
* @throws GLException if no implementation for the given profile is found.
*/
public static final GLProfile get(String[] profiles)
throws GLException
{
for(int i=0; i*/ mappedProfiles;
/**
* Tries the profiles implementation and native libraries.
* Throws an GLException if no profile could be found at all.
*/
static {
// run the whole static initialization privileged to speed up,
// since this skips checking further access
AccessController.doPrivileged(new PrivilegedAction() {
public Object run() {
JVMUtil.initSingleton();
AccessControlContext acc = AccessController.getContext();
isAWTAvailable = NativeWindowFactory.isAWTAvailable() &&
ReflectionUtil.isClassAvailable("javax.media.opengl.awt.GLCanvas") ; // JOGL
boolean hasDesktopGL = false;
boolean hasDesktopGLES12 = false;
boolean hasNativeOSFactory = false;
Throwable t;
//
// First iteration of desktop GL availability detection
// - native libs exist
// - class exists
//
t=null;
try {
// See DRIHack.java for an explanation of why this is necessary
DRIHack.begin();
GLJNILibLoader.loadGLDesktop();
DRIHack.end();
hasDesktopGL = true;
} catch (UnsatisfiedLinkError ule) {
t=ule;
} catch (SecurityException se) {
t=se;
} catch (NullPointerException npe) {
t=npe;
} catch (RuntimeException re) {
t=re;
}
if(null!=t) {
if (DEBUG) {
System.err.println("GLProfile.static Desktop GL Library not available");
t.printStackTrace();
}
}
t=null;
try {
// See DRIHack.java for an explanation of why this is necessary
DRIHack.begin();
GLJNILibLoader.loadGLDesktopES12();
DRIHack.end();
hasDesktopGLES12 = true;
} catch (UnsatisfiedLinkError ule) {
t=ule;
} catch (SecurityException se) {
t=se;
} catch (NullPointerException npe) {
t=npe;
} catch (RuntimeException re) {
t=re;
}
if(DEBUG && null!=t) {
System.err.println("GLProfile.static Desktop GLES12 Library not available");
t.printStackTrace();
}
hasGL234Impl = hasDesktopGL && ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.gl4.GL4bcImpl");
hasGL4bcImpl = hasGL234Impl;
hasGL4Impl = hasGL234Impl;
hasGL3bcImpl = hasGL234Impl;
hasGL3Impl = hasGL234Impl;
hasGL2Impl = hasGL234Impl;
hasGL2ES12Impl = hasDesktopGLES12 && ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.gl2es12.GL2ES12Impl");
mappedProfiles = computeProfileMap();
//
// Second iteration of desktop GL availability detection
// utilizing the detected GL version in the shared context.
//
// - Instantiate GLDrawableFactory incl its shared dummy drawable/context,
// which will register at GLContext ..
//
if(hasDesktopGL||hasDesktopGLES12) {
t=null;
// if successfull it has a shared dummy drawable and context created
try {
hasNativeOSFactory = null != GLDrawableFactory.getFactoryImpl(GL2);
} catch (LinkageError le) {
t=le;
} catch (RuntimeException re) {
t=re;
}
if(DEBUG && null!=t) {
System.err.println("GLProfile.static - Native platform GLDrawable factory not available");
t.printStackTrace();
}
}
if(hasNativeOSFactory && !GLContext.mappedVersionsAvailableSet) {
// nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent},
// so we have to add the usual suspect
GLContext.mapVersionAvailable(2, GLContext.CTX_PROFILE_COMPAT, 1, 5, GLContext.CTX_PROFILE_COMPAT|GLContext.CTX_OPTION_ANY);
}
if(!hasNativeOSFactory) {
hasDesktopGL = false;
hasGL234Impl = false;
hasGL4bcImpl = false;
hasGL4Impl = false;
hasGL3bcImpl = false;
hasGL3Impl = false;
hasGL2ES12Impl = false;
hasGL2Impl = false;
} else {
hasGL4bcImpl = hasGL4bcImpl && GLContext.isGL4bcAvailable();
hasGL4Impl = hasGL4Impl && GLContext.isGL4Available();
hasGL3bcImpl = hasGL3bcImpl && GLContext.isGL3bcAvailable();
hasGL3Impl = hasGL3Impl && GLContext.isGL3Available();
hasGL2Impl = hasGL2Impl && GLContext.isGL2Available();
hasGL2ES12Impl = hasGL2ES12Impl && GLContext.isGL2Available();
}
boolean hasEGLDynLookup = ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.egl.EGLDynamicLookupHelper");
boolean hasEGLDrawableFactory = false;
boolean btest = false;
if(hasEGLDynLookup) {
t=null;
try {
hasEGLDrawableFactory = null!=GLDrawableFactory.getFactoryImpl(GLES2);
btest = hasEGLDrawableFactory &&
ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.es2.GLES2Impl") &&
null!=com.jogamp.opengl.impl.egl.EGLDynamicLookupHelper.getDynamicLookupHelper(2);
} catch (LinkageError le) {
t=le;
} catch (SecurityException se) {
t=se;
} catch (NullPointerException npe) {
t=npe;
} catch (RuntimeException re) {
t=re;
}
if(DEBUG && null!=t) {
System.err.println("GLProfile.static - GL ES2 Factory/Library not available");
t.printStackTrace();
}
}
hasGLES2Impl = btest;
if(hasGLES2Impl) {
GLContext.mapVersionAvailable(2, GLContext.CTX_PROFILE_ES, 2, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY);
}
btest = false;
if(hasEGLDynLookup) {
t=null;
try {
btest = hasEGLDrawableFactory &&
ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.es1.GLES1Impl") &&
null!=com.jogamp.opengl.impl.egl.EGLDynamicLookupHelper.getDynamicLookupHelper(1);
} catch (LinkageError le) {
t=le;
} catch (SecurityException se) {
t=se;
} catch (NullPointerException npe) {
t=npe;
} catch (RuntimeException re) {
t=re;
}
if(DEBUG && null!=t) {
System.err.println("GLProfile.static - GL ES1 Factory/Library not available");
t.printStackTrace();
}
}
hasGLES1Impl = btest;
if(hasGLES1Impl) {
GLContext.mapVersionAvailable(1, GLContext.CTX_PROFILE_ES, 1, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY);
}
mappedProfiles = computeProfileMap();
if (DEBUG) {
System.err.println("GLProfile.static isAWTAvailable "+isAWTAvailable);
System.err.println("GLProfile.static hasNativeOSFactory "+hasNativeOSFactory);
System.err.println("GLProfile.static hasDesktopGL "+hasDesktopGL);
System.err.println("GLProfile.static hasDesktopGLES12 "+hasDesktopGLES12);
System.err.println("GLProfile.static hasEGLDynLookup "+hasEGLDynLookup);
System.err.println("GLProfile.static hasEGLDrawableFactory "+hasEGLDrawableFactory);
System.err.println("GLProfile.static hasGL234Impl "+hasGL234Impl);
System.err.println("GLProfile.static "+glAvailabilityToString());
}
return null;
}
});
if(null==defaultGLProfile) {
throw new GLException("No profile available: "+list2String(GL_PROFILE_LIST_ALL)+", "+glAvailabilityToString());
}
}
private static final String list2String(String[] list) {
StringBuffer msg = new StringBuffer();
msg.append("[");
for (int i = 0; i < list.length; i++) {
if (i > 0)
msg.append(", ");
msg.append(list[i]);
}
msg.append("]");
return msg.toString();
}
private static HashMap computeProfileMap() {
defaultGLProfile=null;
HashMap/**/ _mappedProfiles = new HashMap(GL_PROFILE_LIST_ALL.length);
for(int i=0; i