/* * 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 * 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 jogamp.nativewindow.NWJNILibLoader; import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; import jogamp.opengl.DesktopGLDynamicLookupHelper; import com.jogamp.common.GlueGenVersion; import com.jogamp.common.jvm.JNILibLoaderBase; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.common.util.VersionUtil; import com.jogamp.common.util.cache.TempJarCache; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveThreadGroupLock; import com.jogamp.nativewindow.NativeWindowVersion; import com.jogamp.opengl.JoglVersion; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeWindowFactory; import javax.media.opengl.fixedfunc.GLPointerFunc; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.HashMap; import java.util.Iterator; import java.util.List; // Added to check if X11 Displays should be closed on exit // Martin C. Hegedus, March 30, 2013 import com.jogamp.opengl.GLRendererQuirks; import jogamp.nativewindow.x11.X11Util; /** * 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 { public static final boolean DEBUG = Debug.debug("GLProfile"); static { // Also initializes TempJarCache if shall be used. Platform.initSingleton(); } /** * Static initialization of JOGL. * *

* This method shall not need to be called for other reasons than having a defined initialization sequence. *

* *

* In case this method is not invoked, GLProfile is initialized implicit by * the first call to {@link #getDefault()}, {@link #get(java.lang.String)}. *

* *

* To initialize JOGL at startup ASAP, this method may be invoked in the main class's * static initializer block, in the static main() method or in the Applet init() method. *

* *

* Since JOGL's initialization is complex and involves multi threading, it is not recommended * to be have it invoked on the AWT EDT thread. In case all JOGL usage is performed * on the AWT EDT, invoke this method outside the AWT EDT - see above. *

* */ public static void initSingleton() { final boolean justInitialized; initLock.lock(); try { if(!initialized) { // volatile: ok initialized = true; justInitialized = true; if(DEBUG) { System.err.println("GLProfile.initSingleton() - thread "+Thread.currentThread().getName()); Thread.dumpStack(); } // run the whole static initialization privileged to speed up, // since this skips checking further access AccessController.doPrivileged(new PrivilegedAction() { public Object run() { Platform.initSingleton(); // Performance hack to trigger classloading of the GL classes impl, which makes up to 12%, 800ms down to 700ms new Thread(new Runnable() { public void run() { final ClassLoader cl = GLProfile.class.getClassLoader(); try { ReflectionUtil.createInstance(getGLImplBaseClassName(GL4bc)+"Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { null, null }, cl); } catch (Throwable t) {} try { ReflectionUtil.createInstance(getGLImplBaseClassName(GLES2)+"Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { null, null }, cl); } catch (Throwable t) {} try { ReflectionUtil.createInstance(getGLImplBaseClassName(GLES1)+"Impl", new Class[] { GLProfile.class, GLContextImpl.class }, new Object[] { null, null }, cl); } catch (Throwable t) {} } }, "GLProfile-GL_Bootstrapping").start(); if(TempJarCache.isInitialized()) { final ClassLoader cl = GLProfile.class.getClassLoader(); // either: [jogl-all.jar, jogl-all-noawt.jar, jogl-all-mobile.jar] -> jogl-all-natives-.jar // or: nativewindow-core.jar -> nativewindow-natives-.jar, // jogl-core.jar -> jogl-natives-.jar, // (newt-core.jar -> newt-natives-.jar)? (if available) final String newtFactoryClassName = "com.jogamp.newt.NewtFactory"; final Class[] classesFromJavaJars = new Class[] { NWJNILibLoader.class, GLProfile.class, null }; if( ReflectionUtil.isClassAvailable(newtFactoryClassName, cl) ) { classesFromJavaJars[2] = ReflectionUtil.getClass(newtFactoryClassName, false, cl); } JNILibLoaderBase.addNativeJarLibs(classesFromJavaJars, "-all", new String[] { "-noawt", "-mobile", "-core" } ); } initProfilesForDefaultDevices(); return null; } }); } else { justInitialized = false; } } finally { initLock.unlock(); } if(DEBUG) { if( justInitialized && ( hasGL234Impl || hasGLES1Impl || hasGLES2Impl ) ) { System.err.println(JoglVersion.getDefaultOpenGLInfo(defaultDevice, null, true)); } } } /** * Trigger eager initialization of GLProfiles for the given device, * in case it isn't done yet. * * @throws GLException if no profile for the given device is available. */ public static void initProfiles(AbstractGraphicsDevice device) throws GLException { getProfileMap(device, true); } /** * Manual shutdown method, may be called after your last JOGL use * within the running JVM.
* It releases all temporary created resources, ie issues {@link javax.media.opengl.GLDrawableFactory#shutdown()}.
* The shutdown implementation is called via the JVM shutdown hook, if not manually invoked.
*

* This method shall not need to be called for other reasons than issuing a proper shutdown of resources at a defined time. *

*/ public static void shutdown() { initLock.lock(); try { if(initialized) { // volatile: ok initialized = false; if(DEBUG) { System.err.println("GLProfile.shutdown() - thread "+Thread.currentThread().getName()); Thread.dumpStack(); } GLDrawableFactory.shutdown(); } } finally { initLock.unlock(); } } // // Query platform available OpenGL implementation // /** * Returns the availability of a profile on a device. * * @param device a valid AbstractGraphicsDevice, or null for the default device. * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), * or [ null, GL ] for the default profile. * @return true if the profile is available for the device, otherwise false. */ public static boolean isAvailable(AbstractGraphicsDevice device, String profile) { initSingleton(); return isAvailableImpl(getProfileMap(device, false), profile); } private static boolean isAvailableImpl(HashMap map, String profile) { return null != map && null != map.get(profile); } /** * Returns the availability of a profile on the default device. * * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), * or [ null, GL ] for the default profile. * @return true if the profile is available for the default device, otherwise false. */ public static boolean isAvailable(String profile) { return isAvailable(null, profile); } /** * Returns the availability of any profile on the default device. * * @return true if any profile is available for the default device, otherwise false. */ public static boolean isAnyAvailable() { return isAvailable(null, null); } public static String glAvailabilityToString(AbstractGraphicsDevice device) { return glAvailabilityToString(device, null).toString(); } public static StringBuilder glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb) { return glAvailabilityToString(device, sb, null, 0); } private static StringBuilder doIndent(StringBuilder sb, String indent, int indentCount) { while(indentCount>0) { sb.append(indent); indentCount--; } return sb; } public static StringBuilder glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb, String indent, int indentCount) { boolean avail; if(null == sb) { sb = new StringBuilder(); } final boolean useIndent = null != indent; initSingleton(); if(null==device) { device = defaultDevice; } final HashMap map = getProfileMap(device, false); if(useIndent) { doIndent(sb, indent, indentCount).append("Native"); indentCount++; doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL4bc").append(indent); } else { sb.append("Native[GL4bc "); } avail=isAvailableImpl(map, GL4bc); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 4, GLContext.CTX_PROFILE_COMPAT); } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL4").append(indent); } else { sb.append(", GL4 "); } avail=isAvailableImpl(map, GL4); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 4, GLContext.CTX_PROFILE_CORE); } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL3bc").append(indent); } else { sb.append(", GL3bc "); } avail=isAvailableImpl(map, GL3bc); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_COMPAT); } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL3").append(indent); } else { sb.append(", GL3 "); } avail=isAvailableImpl(map, GL3); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 3, GLContext.CTX_PROFILE_CORE); } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL2").append(indent); } else { sb.append(", GL2 "); } avail=isAvailableImpl(map, GL2); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 2, GLContext.CTX_PROFILE_COMPAT); } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL2ES1").append(indent); } else { sb.append(", GL2ES1 "); } sb.append(isAvailableImpl(map, GL2ES1)); if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GLES1").append(indent); } else { sb.append(", GLES1 "); } avail=isAvailableImpl(map, GLES1); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 1, GLContext.CTX_PROFILE_ES); } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GL2ES2").append(indent); } else { sb.append(", GL2ES2 "); } sb.append(isAvailableImpl(map, GL2ES2)); if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("GLES2").append(indent); } else { sb.append(", GLES2 "); } avail=isAvailableImpl(map, GLES2); sb.append(avail); if(avail) { glAvailabilityToString(device, sb.append(" "), 2, GLContext.CTX_PROFILE_ES); } if(useIndent) { indentCount--; doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("Profiles"); indentCount++; } else { sb.append("], Profiles["); } if(null != map) { for(Iterator i=map.values().iterator(); i.hasNext(); ) { if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount); } sb.append(i.next().toString()); if(!useIndent) { sb.append(", "); } } if(useIndent) { doIndent(sb.append(Platform.getNewline()), indent, indentCount).append("default "); } else { sb.append(", default "); } try { sb.append(getDefault(device)); } catch (GLException gle) { sb.append("n/a"); } } if(useIndent) { sb.append(Platform.getNewline()); } else { sb.append("]"); } return sb; } /** Uses the default device */ public static String glAvailabilityToString() { return glAvailabilityToString(null); } // // 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"; /** The default profile, used for the device default profile map */ private static final String GL_DEFAULT = "GL_DEFAULT"; /** * All GL Profiles in the order of default detection. * Desktop compatibility profiles (the one with fixed function pipeline) comes first * from highest to lowest version. *

This includes the generic subset profiles GL2GL3, GL2ES2 and GL2ES1.

* *
    *
  • GL4bc *
  • GL3bc *
  • GL2 *
  • GL4 *
  • GL3 *
  • GL2GL3 *
  • GLES2 *
  • GL2ES2 *
  • GLES1 *
  • GL2ES1 *
* */ public static final String[] GL_PROFILE_LIST_ALL = new String[] { GL4bc, GL3bc, GL2, GL4, GL3, GL2GL3, GLES2, GL2ES2, GLES1, GL2ES1 }; /** * Order of maximum profiles. * *
    *
  • GL4bc *
  • GL4 *
  • GL3bc *
  • GL3 *
  • GL2 *
  • GLES2 *
  • GLES1 *
* */ public static final String[] GL_PROFILE_LIST_MAX = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GLES2, GLES1 }; /** * Order of minimum profiles. * *
    *
  • GLES1 *
  • GLES2 *
  • GL2 *
  • GL3 *
  • GL3bc *
  • GL4 *
  • GL4bc *
* */ public static final String[] GL_PROFILE_LIST_MIN = new String[] { GLES1, GLES2, GL2, GL3, GL3bc, GL4, GL4bc }; /** * Order of minimum original desktop profiles. * *
    *
  • GL2 *
  • GL3bc *
  • GL4bc *
  • GL3 *
  • GL4 *
* */ public static final String[] GL_PROFILE_LIST_MIN_DESKTOP = new String[] { GL2, GL3bc, GL4bc, GL3, GL4 }; /** * Order of maximum fixed function profiles * *
    *
  • GL4bc *
  • GL3bc *
  • GL2 *
  • GLES1 *
* */ public static final String[] GL_PROFILE_LIST_MAX_FIXEDFUNC = new String[] { GL4bc, GL3bc, GL2, GLES1 }; /** * Order of maximum programmable shader profiles * *
    *
  • GL4bc *
  • GL4 *
  • GL3bc *
  • GL3 *
  • GL2 *
  • GLES2 *
* */ public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER = new String[] { GL4bc, GL4, GL3bc, GL3, GL2, GLES2 }; /** * Order of maximum programmable shader core only profiles * *
    *
  • GL4 *
  • GL3 *
  • GLES2 *
* */ public static final String[] GL_PROFILE_LIST_MAX_PROGSHADER_CORE = new String[] { GL4, GL3, GLES2 }; /** 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} * and favors hardware acceleration. * @throws GLException if no profile is available for the device. * @see #GL_PROFILE_LIST_ALL */ public static GLProfile getDefault(AbstractGraphicsDevice device) { GLProfile glp = get(device, GL_DEFAULT); return glp; } /** 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} * and favors hardware acceleration. *

Uses the default device.

* @throws GLException if no profile is available for the default device. */ public static GLProfile getDefault() { return getDefault(defaultDevice); } /** * Returns the highest profile. * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX} * * @throws GLException if no profile is available for the device. * @see #GL_PROFILE_LIST_MAX */ public static GLProfile getMaximum(AbstractGraphicsDevice device, boolean favorHardwareRasterizer) throws GLException { return get(device, GL_PROFILE_LIST_MAX, favorHardwareRasterizer); } /** Uses the default device * @throws GLException if no profile is available for the default device. * @see #GL_PROFILE_LIST_MAX */ public static GLProfile getMaximum(boolean favorHardwareRasterizer) throws GLException { return get(GL_PROFILE_LIST_MAX, favorHardwareRasterizer); } /** * Returns the lowest profile. * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MIN} * * @throws GLException if no desktop profile is available for the device. * @see #GL_PROFILE_LIST_MIN */ public static GLProfile getMinimum(AbstractGraphicsDevice device, boolean favorHardwareRasterizer) throws GLException { return get(device, GL_PROFILE_LIST_MIN, favorHardwareRasterizer); } /** Uses the default device * @throws GLException if no desktop profile is available for the default device. * @see #GL_PROFILE_LIST_MIN */ public static GLProfile getMinimum(boolean favorHardwareRasterizer) throws GLException { return get(GL_PROFILE_LIST_MIN, favorHardwareRasterizer); } /** * 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 fixed function profile is available for the device. * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC */ public static GLProfile getMaxFixedFunc(AbstractGraphicsDevice device, boolean favorHardwareRasterizer) throws GLException { return get(device, GL_PROFILE_LIST_MAX_FIXEDFUNC, favorHardwareRasterizer); } /** Uses the default device * @throws GLException if no fixed function profile is available for the default device. * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC */ public static GLProfile getMaxFixedFunc(boolean favorHardwareRasterizer) throws GLException { return get(GL_PROFILE_LIST_MAX_FIXEDFUNC, favorHardwareRasterizer); } /** * 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 programmable profile is available for the device. * @see #GL_PROFILE_LIST_MAX_PROGSHADER */ public static GLProfile getMaxProgrammable(AbstractGraphicsDevice device, boolean favorHardwareRasterizer) throws GLException { return get(device, GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer); } /** Uses the default device * @throws GLException if no programmable profile is available for the default device. * @see #GL_PROFILE_LIST_MAX_PROGSHADER */ public static GLProfile getMaxProgrammable(boolean favorHardwareRasterizer) throws GLException { return get(GL_PROFILE_LIST_MAX_PROGSHADER, favorHardwareRasterizer); } /** * Returns the highest profile, implementing the programmable shader core pipeline only. * It selects the first of the set: {@link GLProfile#GL_PROFILE_LIST_MAX_PROGSHADER_CORE} * * @throws GLException if no programmable core profile is available for the device. * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE */ public static GLProfile getMaxProgrammableCore(AbstractGraphicsDevice device, boolean favorHardwareRasterizer) throws GLException { return get(device, GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer); } /** Uses the default device * @throws GLException if no programmable core profile is available for the default device. * @see #GL_PROFILE_LIST_MAX_PROGSHADER_CORE */ public static GLProfile getMaxProgrammableCore(boolean favorHardwareRasterizer) throws GLException { return get(GL_PROFILE_LIST_MAX_PROGSHADER_CORE, favorHardwareRasterizer); } /** * Returns the GL2ES1 profile implementation, hence compatible w/ GL2ES1.
* It returns: *
     *   GLProfile.get(device, GLProfile.GL2ES1).getImpl());
     * 
*

Selection favors hardware rasterizer.

* * @throws GLException if no GL2ES1 compatible profile is available for the default device. * @see #isGL2ES1() * @see #get(AbstractGraphicsDevice, String) * @see #getImpl() */ public static GLProfile getGL2ES1(AbstractGraphicsDevice device) throws GLException { return get(device, GL2ES1).getImpl(); } /** * Calls {@link #getGL2ES1(AbstractGraphicsDevice)} using the default device. *

Selection favors hardware rasterizer.

* @see #getGL2ES1(AbstractGraphicsDevice) */ public static GLProfile getGL2ES1() throws GLException { return get(defaultDevice, GL2ES1).getImpl(); } /** * Returns the GL2ES2 profile implementation, hence compatible w/ GL2ES2.
* It returns: *
     *   GLProfile.get(device, GLProfile.GL2ES2).getImpl());
     * 
*

Selection favors hardware rasterizer.

* * @throws GLException if no GL2ES2 compatible profile is available for the default device. * @see #isGL2ES2() * @see #get(AbstractGraphicsDevice, String) * @see #getImpl() */ public static GLProfile getGL2ES2(AbstractGraphicsDevice device) throws GLException { return get(device, GL2ES2).getImpl(); } /** * Calls {@link #getGL2ES2(AbstractGraphicsDevice)} using the default device. *

Selection favors hardware rasterizer.

* @see #getGL2ES2(AbstractGraphicsDevice) */ public static GLProfile getGL2ES2() throws GLException { return get(defaultDevice, GL2ES2).getImpl(); } /** * Returns the GL2GL3 profile implementation, hence compatible w/ GL2GL3.
* It returns: *
     *   GLProfile.get(device, GLProfile.GL2GL3).getImpl());
     * 
*

Selection favors hardware rasterizer.

* * @throws GLException if no GL2GL3 compatible profile is available for the default device. * @see #isGL2GL3() * @see #get(AbstractGraphicsDevice, String) * @see #getImpl() */ public static GLProfile getGL2GL3(AbstractGraphicsDevice device) throws GLException { return get(device, GL2GL3).getImpl(); } /** * Calls {@link #getGL2GL3(AbstractGraphicsDevice)} using the default device. *

Selection favors hardware rasterizer.

* @see #getGL2GL3(AbstractGraphicsDevice) */ public static GLProfile getGL2GL3() throws GLException { return get(defaultDevice, GL2GL3).getImpl(); } /** Returns a GLProfile object. * verifies the given profile and chooses an appropriate implementation. * A generic value of null or GL will result in * the default profile. * * @param device a valid AbstractGraphicsDevice, or null for the default device. * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), * or [ null, GL ] for the default profile. * @throws GLException if the requested profile is not available for the device. */ public static GLProfile get(AbstractGraphicsDevice device, String profile) throws GLException { if(null==profile || profile.equals("GL")) { profile = GL_DEFAULT; } final HashMap glpMap = getProfileMap(device, true); final GLProfile glp = glpMap.get(profile); if(null == glp) { throw new GLException("Profile "+profile+" is not available on "+device+", but: "+glpMap.values()); } return glp; } /** Uses the default device * @param profile a valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..), * or [ null, GL ] for the default profile. * @throws GLException if the requested profile is not available for the default device. */ public static GLProfile get(String profile) throws GLException { return get(defaultDevice, profile); } /** * Returns the first profile from the given list, * where an implementation is available. * * @param device a valid AbstractGraphicsDevice, or null for the default device. * @param profiles array of valid GLProfile name ({@link #GL4bc}, {@link #GL4}, {@link #GL2}, ..) * @param favorHardwareRasterizer set to true, if hardware rasterizer shall be favored, otherwise false. * @throws GLException if the non of the requested profiles is available for the device. */ public static GLProfile get(AbstractGraphicsDevice device, String[] profiles, boolean favorHardwareRasterizer) throws GLException { GLProfile glProfileAny = null; HashMap map = getProfileMap(device, true); for(int i=0; i map = deviceConn2ProfileMap.get(deviceKey); if( null == map ) { throw new InternalError("GLContext Avail. GLVersion is set - but no profile map for device: "+device); } return null != map.get(GL_DEFAULT); } boolean addedDesktopProfile = false; boolean addedEGLProfile = false; final boolean deviceIsDesktopCompatible = hasDesktopGLFactory && desktopFactory.getIsDeviceCompatible(device); if( deviceIsDesktopCompatible ) { // 1st pretend we have all Desktop and EGL profiles .. computeProfileMap(device, true /* desktopCtxUndef*/, true /* esCtxUndef */); // Triggers eager initialization of share context in GLDrawableFactory for the device, // hence querying all available GLProfiles final Thread sharedResourceThread = desktopFactory.getSharedResourceThread(); if(null != sharedResourceThread) { initLock.addOwner(sharedResourceThread); } boolean desktopSharedCtxAvail = desktopFactory.createSharedResource(device); if(null != sharedResourceThread) { initLock.removeOwner(sharedResourceThread); } if (DEBUG) { System.err.println("GLProfile.initProfilesForDevice: "+device+": desktop Shared Ctx "+desktopSharedCtxAvail); } if(!desktopSharedCtxAvail) { hasDesktopGLFactory = false; } else if( !GLContext.getAvailableGLVersionsSet(device) ) { throw new InternalError("Available GLVersions not set"); } addedDesktopProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); } final boolean deviceIsEGLCompatible = hasEGLFactory && eglFactory.getIsDeviceCompatible(device); // also test GLES1 and GLES2 on desktop, since we have implementations / emulations available. if( deviceIsEGLCompatible && ( hasGLES2Impl || hasGLES1Impl ) ) { // 1st pretend we have all EGL profiles .. computeProfileMap(device, false /* desktopCtxUndef*/, true /* esCtxUndef */); // Triggers eager initialization of share context in GLDrawableFactory for the device, // hence querying all available GLProfiles final Thread sharedResourceThread = eglFactory.getSharedResourceThread(); if(null != sharedResourceThread) { initLock.addOwner(sharedResourceThread); } boolean eglSharedCtxAvail = eglFactory.createSharedResource(device); if(null != sharedResourceThread) { initLock.removeOwner(sharedResourceThread); } if(!eglSharedCtxAvail) { // Remark: On Windows there is a libEGL.dll delivered w/ Chrome 15.0.874.121m and Firefox 8.0.1 // but it seems even EGL.eglInitialize(eglDisplay, null, null) // fails in some scenarios (eg VirtualBox 4.1.6) w/ EGL error 0x3001 (EGL_NOT_INITIALIZED). hasEGLFactory = false; hasGLES2Impl = false; hasGLES1Impl = false; } if (DEBUG) { System.err.println("GLProfile.initProfilesForDevice: "+device+": egl Shared Ctx "+eglSharedCtxAvail); } addedEGLProfile = computeProfileMap(device, false /* desktopCtxUndef*/, false /* esCtxUndef */); } if( !addedDesktopProfile && !addedEGLProfile ) { setProfileMap(device, new HashMap()); // empty if(DEBUG) { System.err.println("GLProfile: device could not be initialized: "+device); System.err.println("GLProfile: compatible w/ desktop: "+deviceIsDesktopCompatible+ ", egl "+deviceIsEGLCompatible); System.err.println("GLProfile: desktoplFactory "+desktopFactory); System.err.println("GLProfile: eglFactory "+eglFactory); System.err.println("GLProfile: hasGLES1Impl "+hasGLES1Impl); System.err.println("GLProfile: hasGLES2Impl "+hasGLES2Impl); } } if(!GLContext.getAvailableGLVersionsSet(device)) { GLContext.setAvailableGLVersionsSet(device); } if (DEBUG) { System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": added profile(s): desktop "+addedDesktopProfile+", egl "+addedEGLProfile); System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": "+glAvailabilityToString(device)); if(addedDesktopProfile) { dumpGLInfo(desktopFactory, device); List availCaps = desktopFactory.getAvailableCapabilities(device); for(int i=0; i availCaps = eglFactory.getAvailableCapabilities(device); for(int i=0; i 0) msg.append(", "); msg.append(list[i]); } msg.append("]"); return msg.toString(); } private static void glAvailabilityToString(AbstractGraphicsDevice device, StringBuilder sb, int major, int profile) { String str = GLContext.getAvailableGLVersionAsString(device, major, profile); if(null==str) { throw new GLException("Internal Error"); } sb.append("["); sb.append(str); sb.append("]"); } private static boolean computeProfileMap(AbstractGraphicsDevice device, boolean desktopCtxUndef, boolean esCtxUndef) { if (DEBUG) { System.err.println("GLProfile.init map "+device.getConnection()+", desktopCtxUndef "+desktopCtxUndef+", esCtxUndef "+esCtxUndef); } final boolean isHardwareRasterizer[] = new boolean[1]; GLProfile defaultGLProfileAny = null; GLProfile defaultGLProfileHW = null; HashMap _mappedProfiles = new HashMap(GL_PROFILE_LIST_ALL.length + 1 /* default */); for(int i=0; i 0; } /** * Returns the profile implementation */ private static String computeProfileImpl(AbstractGraphicsDevice device, String profile, boolean desktopCtxUndef, boolean esCtxUndef, boolean isHardwareRasterizer[]) { // OSX GL3.. doesn't support GLSL<150, // hence GL2ES2 and GL2GL3 need to be mapped on GL2 on OSX for GLSL compatibility. final boolean isOSX = Platform.OS_TYPE == Platform.OSType.MACOS; if (GL2ES1.equals(profile)) { final boolean es1HardwareRasterizer[] = new boolean[1]; final boolean gles1Available = hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, es1HardwareRasterizer) ); final boolean gles1HWAvailable = gles1Available && es1HardwareRasterizer[0] ; if(hasGL234Impl) { if(GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) { if(!gles1HWAvailable || isHardwareRasterizer[0]) { return GL4bc; } } if(GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) { if(!gles1HWAvailable || isHardwareRasterizer[0]) { return GL3bc; } } if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) { if(!gles1HWAvailable || isHardwareRasterizer[0]) { return GL2; } } } if(gles1Available) { isHardwareRasterizer[0] = es1HardwareRasterizer[0]; return GLES1; } } else if (GL2ES2.equals(profile)) { final boolean es2HardwareRasterizer[] = new boolean[1]; final boolean gles2Available = hasGLES2Impl && ( esCtxUndef || GLContext.isGLES2Available(device, es2HardwareRasterizer) ); final boolean gles2HWAvailable = gles2Available && es2HardwareRasterizer[0] ; if(hasGL234Impl) { if(!isOSX) { if(GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) { if(!gles2HWAvailable || isHardwareRasterizer[0]) { return GL4bc; } } if(GLContext.isGL4Available(device, isHardwareRasterizer)) { if(!gles2HWAvailable || isHardwareRasterizer[0]) { return GL4; } } if(GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) { if(!gles2HWAvailable || isHardwareRasterizer[0]) { return GL3bc; } } if(GLContext.isGL3Available(device, isHardwareRasterizer)) { if(!gles2HWAvailable || isHardwareRasterizer[0]) { return GL3; } } } if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) { if(!gles2HWAvailable || isHardwareRasterizer[0]) { return GL2; } } } if(gles2Available) { isHardwareRasterizer[0] = es2HardwareRasterizer[0]; return GLES2; } } else if(GL2GL3.equals(profile)) { if(hasGL234Impl) { if(!isOSX && GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) { return GL4bc; } else if(!isOSX && GLContext.isGL4Available(device, isHardwareRasterizer)) { return GL4; } else if(!isOSX && GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) { return GL3bc; } else if(!isOSX && GLContext.isGL3Available(device, isHardwareRasterizer)) { return GL3; } else if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) { return GL2; } } } else if(GL4bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device, isHardwareRasterizer))) { return GL4bc; } else if(GL4.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) { return GL4; } else if(GL3bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) { return GL3bc; } else if(GL3.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) { return GL3; } else if(GL2.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) { return GL2; } else if(GLES2.equals(profile) && hasGLES2Impl && ( esCtxUndef || GLContext.isGLES2Available(device, isHardwareRasterizer))) { return GLES2; } else if(GLES1.equals(profile) && hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, isHardwareRasterizer))) { return GLES1; } return null; } private static /*final*/ HashMap> deviceConn2ProfileMap = new HashMap>(); /** * This implementation support lazy initialization, while avoiding recursion/deadlocks.
* If no mapping 'device -> GLProfiles-Map' exists yet, it triggers
* - create empty mapping device -> GLProfiles-Map
* - initialization GLProfiles-Map' * @param throwExceptionOnZeroProfile true if GLException shall be thrown in case of no mapped profile, otherwise false. * @return the GLProfile HashMap if exists, otherwise null * @throws GLException if no profile for the given device is available. */ private static HashMap getProfileMap(AbstractGraphicsDevice device, boolean throwExceptionOnZeroProfile) throws GLException { initSingleton(); if(null==defaultDevice) { // avoid NPE and notify of incomplete initialization throw new GLException("No default device available"); } if(null==device) { device = defaultDevice; } final String deviceKey = device.getUniqueID(); HashMap map = deviceConn2ProfileMap.get(deviceKey); if( null != map ) { return map; } if( !initProfilesForDevice(device) ) { if( throwExceptionOnZeroProfile ) { throw new GLException("No Profile available for "+device); } else { return null; } } map = deviceConn2ProfileMap.get(deviceKey); if( null == map && throwExceptionOnZeroProfile ) { throw new InternalError("initProfilesForDevice(..) didn't setProfileMap(..) for "+device); } return map; } private static void setProfileMap(AbstractGraphicsDevice device, HashMap mappedProfiles) { synchronized ( deviceConn2ProfileMap ) { deviceConn2ProfileMap.put(device.getUniqueID(), mappedProfiles); } } private GLProfile(String profile, GLProfile profileImpl, boolean isHardwareRasterizer) { this.profile = profile; this.profileImpl = profileImpl; this.isHardwareRasterizer = isHardwareRasterizer; } private final GLProfile profileImpl; private final String profile; private final boolean isHardwareRasterizer; }