getGLCtor(boolean glObject) {
return getGLCtor(getImplName(), glObject);
}
private static final Constructor> getGLCtor(String profileImpl, boolean glObject) {
if( GLES2 == profileImpl || GLES3 == profileImpl ) {
return glObject ? ctorGLES3Impl : ctorGLES3ProcAddr;
} else if( GLES1 == profileImpl ) {
return glObject ? ctorGLES1Impl : ctorGLES1ProcAddr;
} else if ( GL4bc == profileImpl ||
GL4 == profileImpl ||
GL3bc == profileImpl ||
GL3 == profileImpl ||
GL2 == profileImpl ) {
return glObject ? ctorGL234Impl : ctorGL234ProcAddr;
} else {
throw new GLException("unsupported profile \"" + profileImpl + "\"");
}
}
/**
* @param o GLProfile object to compare with
* @return true if given Object is a GLProfile and
* if both, profile and profileImpl is equal with this.
*/
@Override
public final boolean equals(Object o) {
if(this==o) { return true; }
if(o instanceof GLProfile) {
final GLProfile glp = (GLProfile)o;
return getName() == glp.getName() && getImplName() == glp.getImplName() ;
}
return false;
}
@Override
public int hashCode() {
int hash = 5;
hash = 97 * hash + getImplName().hashCode();
hash = 97 * hash + getName().hashCode();
return hash;
}
/**
* @param glp GLProfile to compare with
* @throws GLException if given GLProfile and this aren't equal
*/
public final void verifyEquality(GLProfile glp) throws GLException {
if(!this.equals(glp)) {
throw new GLException("GLProfiles are not equal: "+this+" != "+glp);
}
}
/** return this profiles name */
public final String getName() {
return profile;
}
/** return this profiles implementation, eg. GL2ES2 -> GL2, or GL3 -> GL3 */
public final GLProfile getImpl() {
return null != profileImpl ? profileImpl : this;
}
/** return true if impl. is a hardware rasterizer, otherwise false. */
public final boolean isHardwareRasterizer() {
return isHardwareRasterizer;
}
/**
* return this profiles implementation name, eg. GL2ES2 -> GL2, or GL3 -> GL3
*/
public final String getImplName() {
return null != profileImpl ? profileImpl.getName() : getName();
}
/** Indicates whether this profile is capable of GL4bc. Includes [ GL4bc ].
*/
public final boolean isGL4bc() {
return GL4bc == profile;
}
/** Indicates whether this profile is capable of GL4. Includes [ GL4bc, GL4 ].
*/
public final boolean isGL4() {
return isGL4bc() || GL4 == profile;
}
/** Indicates whether this profile is capable of GL3bc. Includes [ GL4bc, GL3bc ].
*/
public final boolean isGL3bc() {
return isGL4bc() || GL3bc == profile;
}
/** Indicates whether this profile is capable of GL3. Includes [ GL4bc, GL4, GL3bc, GL3 ].
*/
public final boolean isGL3() {
return isGL4() || isGL3bc() || GL3 == profile;
}
/** Indicates whether this profile is capable of GL2 . Includes [ GL4bc, GL3bc, GL2 ].
*/
public final boolean isGL2() {
return isGL3bc() || GL2 == profile;
}
/** Indicates whether this profile is capable of GLES1. Includes [ GLES1 ].
*/
public final boolean isGLES1() {
return GLES1 == profile;
}
/** Indicates whether this profile is capable of GLES2. Includes [ GLES2, GLES3 ].
*/
public final boolean isGLES2() {
return isGLES3() || GLES2 == profile;
}
/** Indicates whether this profile is capable of GLES3. Includes [ GLES3 ].
*/
public final boolean isGLES3() {
return GLES3 == profile;
}
/** Indicates whether this profile is capable of GLES. Includes [ GLES1, GLES2, GLES3 ].
*/
public final boolean isGLES() {
return GLES3 == profile || GLES2 == profile || GLES1 == profile;
}
/** Indicates whether this profile is capable of GL2ES1. Includes [ GL4bc, GL3bc, GL2, GLES1, GL2ES1 ].
*/
public final boolean isGL2ES1() {
return GL2ES1 == profile || isGLES1() || isGL2();
}
/** Indicates whether this profile is capable of GL2GL3. Includes [ GL4bc, GL4, GL3bc, GL3, GL2, GL2GL3 ].
*/
public final boolean isGL2GL3() {
return GL2GL3 == profile || isGL3() || isGL2();
}
/** Indicates whether this profile is capable of GL2ES2. Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL2, GL2GL3, GL2ES2, GLES2 ].
*/
public final boolean isGL2ES2() {
return GL2ES2 == profile || isGLES2() || isGL2GL3();
}
/**
* Indicates whether this profile is capable of GL2ES3. Includes [ GL4bc, GL4, GL3bc, GL3, GLES3, GL3ES3, GL2, GL2GL3 ].
* @see #isGL3ES3()
* @see #isGL2GL3()
*/
public final boolean isGL2ES3() {
return isGL3ES3() || isGL2GL3();
}
/** Indicates whether this profile is capable of GL3ES3. Includes [ GL4bc, GL4, GL3bc, GL3, GLES3 ].
*/
public final boolean isGL3ES3() {
return isGL4ES3() || isGL3();
}
/** Indicates whether this profile is capable of GL4ES3. Includes [ GL4bc, GL4, GLES3 ].
*/
public final boolean isGL4ES3() {
return GL4ES3 == profile || isGLES3() || isGL4();
}
/** Indicates whether this profile supports GLSL, i.e. {@link #isGL2ES2()}. */
public final boolean hasGLSL() {
return isGL2ES2() ;
}
/** Indicates whether this profile uses the native OpenGL ES1 implementations. */
public final boolean usesNativeGLES1() {
return GLES1 == getImplName();
}
/** Indicates whether this profile uses the native OpenGL ES2 implementations. */
public final boolean usesNativeGLES2() {
return GLES2 == getImplName();
}
/** Indicates whether this profile uses the native OpenGL ES3 implementations. */
public final boolean usesNativeGLES3() {
return GLES3 == getImplName();
}
/** Indicates whether this profile uses either of the native OpenGL ES implementations. */
public final boolean usesNativeGLES() {
return usesNativeGLES3() || usesNativeGLES2() || usesNativeGLES1();
}
/**
* General validation if type is a valid GL data type
* for the current profile
*/
public boolean isValidDataType(int type, boolean throwException) {
switch(type) {
case GL.GL_UNSIGNED_BYTE:
case GL.GL_BYTE:
case GL.GL_UNSIGNED_SHORT:
case GL.GL_SHORT:
case GL.GL_FLOAT:
case GL.GL_FIXED:
return true;
case javax.media.opengl.GL2ES2.GL_INT:
case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
if( isGL2ES2() ) {
return true;
}
case javax.media.opengl.GL2.GL_DOUBLE:
if( isGL3() ) {
return true;
}
case javax.media.opengl.GL2.GL_2_BYTES:
case javax.media.opengl.GL2.GL_3_BYTES:
case javax.media.opengl.GL2.GL_4_BYTES:
if( isGL2() ) {
return true;
}
}
if(throwException) {
throw new GLException("Illegal data type on profile "+this+": "+type);
}
return false;
}
public boolean isValidArrayDataType(int index, int comps, int type,
boolean isVertexAttribPointer, boolean throwException) {
final String arrayName = getGLArrayName(index);
if( isGLES1() ) {
if(isVertexAttribPointer) {
if(throwException) {
throw new GLException("Illegal array type for "+arrayName+" on profile GLES1: VertexAttribPointer");
}
return false;
}
switch(index) {
case GLPointerFunc.GL_VERTEX_ARRAY:
case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
switch(type) {
case GL.GL_BYTE:
case GL.GL_SHORT:
case GL.GL_FIXED:
case GL.GL_FLOAT:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
}
return false;
}
switch(comps) {
case 0:
case 2:
case 3:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
}
return false;
}
break;
case GLPointerFunc.GL_NORMAL_ARRAY:
switch(type) {
case GL.GL_BYTE:
case GL.GL_SHORT:
case GL.GL_FIXED:
case GL.GL_FLOAT:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
}
return false;
}
switch(comps) {
case 0:
case 3:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
}
return false;
}
break;
case GLPointerFunc.GL_COLOR_ARRAY:
switch(type) {
case GL.GL_UNSIGNED_BYTE:
case GL.GL_FIXED:
case GL.GL_FLOAT:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GLES1: "+type);
}
return false;
}
switch(comps) {
case 0:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
}
return false;
}
break;
}
} else if( isGLES2() ) {
// simply ignore !isVertexAttribPointer case, since it is simulated anyway ..
switch(type) {
case GL.GL_UNSIGNED_BYTE:
case GL.GL_BYTE:
case GL.GL_UNSIGNED_SHORT:
case GL.GL_SHORT:
case GL.GL_FLOAT:
case GL.GL_FIXED:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GLES2: "+type);
}
return false;
}
/** unable to validate .. could be any valid type/component combination
switch(comps) {
case 0:
case 1:
case 2:
case 3:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GLES2: "+comps);
}
return false;
} */
} else if( isGL2ES2() ) {
if(isVertexAttribPointer) {
switch(type) {
case GL.GL_UNSIGNED_BYTE:
case GL.GL_BYTE:
case GL.GL_UNSIGNED_SHORT:
case GL.GL_SHORT:
case GL.GL_FLOAT:
case javax.media.opengl.GL2ES2.GL_INT:
case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
case javax.media.opengl.GL2.GL_DOUBLE:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
}
return false;
}
switch(comps) {
case 0:
case 1:
case 2:
case 3:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
}
return false;
}
} else {
switch(index) {
case GLPointerFunc.GL_VERTEX_ARRAY:
switch(type) {
case GL.GL_SHORT:
case GL.GL_FLOAT:
case javax.media.opengl.GL2ES2.GL_INT:
case javax.media.opengl.GL2.GL_DOUBLE:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
}
return false;
}
switch(comps) {
case 0:
case 2:
case 3:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
}
return false;
}
break;
case GLPointerFunc.GL_NORMAL_ARRAY:
switch(type) {
case GL.GL_BYTE:
case GL.GL_SHORT:
case GL.GL_FLOAT:
case javax.media.opengl.GL2ES2.GL_INT:
case javax.media.opengl.GL2.GL_DOUBLE:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
}
return false;
}
switch(comps) {
case 0:
case 3:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GLES1: "+comps);
}
return false;
}
break;
case GLPointerFunc.GL_COLOR_ARRAY:
switch(type) {
case GL.GL_UNSIGNED_BYTE:
case GL.GL_BYTE:
case GL.GL_UNSIGNED_SHORT:
case GL.GL_SHORT:
case GL.GL_FLOAT:
case javax.media.opengl.GL2ES2.GL_INT:
case javax.media.opengl.GL2ES2.GL_UNSIGNED_INT:
case javax.media.opengl.GL2.GL_DOUBLE:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
}
return false;
}
switch(comps) {
case 0:
case 3:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
}
return false;
}
break;
case GLPointerFunc.GL_TEXTURE_COORD_ARRAY:
switch(type) {
case GL.GL_SHORT:
case GL.GL_FLOAT:
case javax.media.opengl.GL2ES2.GL_INT:
case javax.media.opengl.GL2.GL_DOUBLE:
break;
default:
if(throwException) {
throw new GLException("Illegal data type for "+arrayName+" on profile GL2: "+type);
}
return false;
}
switch(comps) {
case 0:
case 1:
case 2:
case 3:
case 4:
break;
default:
if(throwException) {
throw new GLException("Illegal component number for "+arrayName+" on profile GL2: "+comps);
}
return false;
}
break;
}
}
}
return true;
}
@Override
public String toString() {
return "GLProfile[" + getName() + "/" + getImplName() + "."+(this.isHardwareRasterizer?"hw":"sw")+"]";
}
private static /*final*/ boolean isAWTAvailable;
private static /*final*/ boolean hasDesktopGLFactory;
private static /*final*/ boolean hasGL234Impl;
private static /*final*/ boolean hasEGLFactory;
private static /*final*/ boolean hasGLES3Impl;
private static /*final*/ boolean hasGLES1Impl;
private static /*final*/ Constructor> ctorGL234Impl;
private static /*final*/ Constructor> ctorGLES3Impl;
private static /*final*/ Constructor> ctorGLES1Impl;
private static /*final*/ Constructor> ctorGL234ProcAddr;
private static /*final*/ Constructor> ctorGLES3ProcAddr;
private static /*final*/ Constructor> ctorGLES1ProcAddr;
private static /*final*/ GLDrawableFactoryImpl eglFactory = null;
private static /*final*/ GLDrawableFactoryImpl desktopFactory = null;
private static /*final*/ AbstractGraphicsDevice defaultDevice = null;
private static boolean initialized = false;
private static final RecursiveThreadGroupLock initLock = LockFactory.createRecursiveThreadGroupLock();
private static final Class>[] ctorGLArgs = new Class>[] { GLProfile.class, jogamp.opengl.GLContextImpl.class };
private static final Class>[] ctorProcArgs = new Class>[] { FunctionAddressResolver.class };
private static final String GL4bcImplClassName = "jogamp.opengl.gl4.GL4bcImpl";
private static final String GL4bcProcClassName = "jogamp.opengl.gl4.GL4bcProcAddressTable";
private static final String GLES1ImplClassName = "jogamp.opengl.es1.GLES1Impl";
private static final String GLES1ProcClassName = "jogamp.opengl.es1.GLES1ProcAddressTable";
private static final String GLES3ImplClassName = "jogamp.opengl.es3.GLES3Impl";
private static final String GLES3ProcClassName = "jogamp.opengl.es3.GLES3ProcAddressTable";
private static final Constructor> getCtor(final String clazzName, final boolean glObject, final ClassLoader cl) {
try {
return ReflectionUtil.getConstructor(clazzName, glObject ? ctorGLArgs : ctorProcArgs, false, cl);
} catch (Throwable t) {
if( DEBUG ) {
System.err.println("Caught: "+t.getMessage());
t.printStackTrace();
}
return null;
}
}
private static final void initGLCtorImpl() {
final ClassLoader classloader = GLProfile.class.getClassLoader();
// depends on hasDesktopGLFactory
{
final Constructor> ctorGL = getCtor(GL4bcImplClassName, true, classloader);
final Constructor> ctorProc = null != ctorGL ? getCtor(GL4bcProcClassName, false, classloader) : null;
if( null != ctorProc ) {
hasGL234Impl = true;
ctorGL234Impl = ctorGL;
ctorGL234ProcAddr = ctorProc;
} else {
hasGL234Impl = false;
ctorGL234Impl = null;
ctorGL234ProcAddr = null;
}
}
// depends on hasEGLFactory
{
final Constructor> ctorGL = getCtor(GLES1ImplClassName, true, classloader);
final Constructor> ctorProc = null != ctorGL ? getCtor(GLES1ProcClassName, false, classloader) : null;
if( null != ctorProc ) {
hasGLES1Impl = true;
ctorGLES1Impl = ctorGL;
ctorGLES1ProcAddr = ctorProc;
} else {
hasGLES1Impl = false;
ctorGLES1Impl = null;
ctorGLES1ProcAddr = null;
}
}
{
final Constructor> ctorGL = getCtor(GLES3ImplClassName, true, classloader);
final Constructor> ctorProc = null != ctorGL ? getCtor(GLES3ProcClassName, false, classloader) : null;
if( null != ctorProc ) {
hasGLES3Impl = true;
ctorGLES3Impl = ctorGL;
ctorGLES3ProcAddr = ctorProc;
} else {
hasGLES3Impl = false;
ctorGLES3Impl = null;
ctorGLES3ProcAddr = null;
}
}
}
/**
* Tries the profiles implementation and native libraries.
*/
private static void initProfilesForDefaultDevices() {
NativeWindowFactory.initSingleton();
if(DEBUG) {
System.err.println("GLProfile.init - thread: " + Thread.currentThread().getName());
System.err.println(VersionUtil.getPlatformInfo());
System.err.println(GlueGenVersion.getInstance());
System.err.println(NativeWindowVersion.getInstance());
System.err.println(JoglVersion.getInstance());
}
final ClassLoader classloader = GLProfile.class.getClassLoader();
isAWTAvailable = NativeWindowFactory.isAWTAvailable() &&
ReflectionUtil.isClassAvailable("javax.media.opengl.awt.GLCanvas", classloader) ; // JOGL
initGLCtorImpl();
//
// 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 ..
//
GLDrawableFactory.initSingleton();
Throwable t=null;
// if successfull it has a shared dummy drawable and context created
try {
desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2);
if(null != desktopFactory) {
DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(0);
if(null!=glLookupHelper) {
hasDesktopGLFactory = glLookupHelper.isLibComplete() && hasGL234Impl;
}
}
} catch (LinkageError le) {
t=le;
} catch (RuntimeException re) {
t=re;
} catch (Throwable tt) {
t=tt;
}
if(DEBUG) {
if(null!=t) {
t.printStackTrace();
}
}
final AbstractGraphicsDevice defaultDesktopDevice;
if(null == desktopFactory) {
hasDesktopGLFactory = false;
hasGL234Impl = false;
defaultDesktopDevice = null;
if(DEBUG) {
System.err.println("Info: GLProfile.init - Desktop GLDrawable factory not available");
}
} else {
defaultDesktopDevice = desktopFactory.getDefaultDevice();
}
if ( ReflectionUtil.isClassAvailable("jogamp.opengl.egl.EGLDrawableFactory", classloader) ) {
t=null;
try {
eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2);
if(null != eglFactory) {
hasEGLFactory = true;
// update hasGLES1Impl, hasGLES3Impl based on EGL
hasGLES3Impl = null!=eglFactory.getGLDynamicLookupHelper(2) && hasGLES3Impl;
hasGLES1Impl = null!=eglFactory.getGLDynamicLookupHelper(1) && hasGLES1Impl;
}
} catch (LinkageError le) {
t=le;
} catch (SecurityException se) {
t=se;
} catch (NullPointerException npe) {
t=npe;
} catch (RuntimeException re) {
t=re;
}
if(DEBUG) {
if(null!=t) {
t.printStackTrace();
}
}
}
final AbstractGraphicsDevice defaultEGLDevice;
if(null == eglFactory) {
hasGLES3Impl = false;
hasGLES1Impl = false;
defaultEGLDevice = null;
if(DEBUG) {
System.err.println("Info: GLProfile.init - EGL GLDrawable factory not available");
}
} else {
defaultEGLDevice = eglFactory.getDefaultDevice();
}
if( null != defaultDesktopDevice ) {
defaultDevice = defaultDesktopDevice;
if(DEBUG) {
System.err.println("Info: GLProfile.init - Default device is desktop derived: "+defaultDevice);
}
} else if ( null != defaultEGLDevice ) {
defaultDevice = defaultEGLDevice;
if(DEBUG) {
System.err.println("Info: GLProfile.init - Default device is EGL derived: "+defaultDevice);
}
} else {
if(DEBUG) {
System.err.println("Info: GLProfile.init - Default device not available");
}
defaultDevice = null;
}
// we require to initialize the EGL device 1st, if available
final boolean addedEGLProfile = null != defaultEGLDevice ? initProfilesForDevice(defaultEGLDevice) : false;
final boolean addedDesktopProfile = null != defaultDesktopDevice ? initProfilesForDevice(defaultDesktopDevice) : false;
final boolean addedAnyProfile = addedEGLProfile || addedDesktopProfile ;
if(DEBUG) {
System.err.println("GLProfile.init addedAnyProfile "+addedAnyProfile+" (desktop: "+addedDesktopProfile+", egl "+addedEGLProfile+")");
System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable);
System.err.println("GLProfile.init hasDesktopGLFactory "+hasDesktopGLFactory);
System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl);
System.err.println("GLProfile.init hasEGLFactory "+hasEGLFactory);
System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl);
System.err.println("GLProfile.init hasGLES3Impl "+hasGLES3Impl);
System.err.println("GLProfile.init defaultDevice "+defaultDevice);
System.err.println("GLProfile.init defaultDevice Desktop "+defaultDesktopDevice);
System.err.println("GLProfile.init defaultDevice EGL "+defaultEGLDevice);
System.err.println("GLProfile.init profile order "+array2String(GL_PROFILE_LIST_ALL));
}
}
/**
* @param device the device for which profiles shall be initialized
* @return true if any profile for the device exists, otherwise false
*/
private static boolean initProfilesForDevice(AbstractGraphicsDevice device) {
if(null == device) {
return false;
}
initLock.lock();
try {
GLDrawableFactory factory = GLDrawableFactory.getFactoryImpl(device);
factory.enterThreadCriticalZone();
try {
return initProfilesForDeviceCritical(device);
} finally {
factory.leaveThreadCriticalZone();
}
} finally {
initLock.unlock();
}
}
private static boolean initProfilesForDeviceCritical(AbstractGraphicsDevice device) {
boolean isSet = GLContext.getAvailableGLVersionsSet(device);
if(DEBUG) {
System.err.println("Info: GLProfile.initProfilesForDevice: "+device+" ("+device.getClass().getName()+"), isSet "+isSet+", hasDesktopGLFactory "+hasDesktopGLFactory+", hasEGLFactory "+hasEGLFactory);
}
if(isSet) {
// Avoid recursion and check whether impl. is sane!
final String deviceKey = device.getUniqueID();
HashMap 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, GLES2 and GLES3 on desktop, since we have implementations / emulations available.
if( deviceIsEGLCompatible && ( hasGLES3Impl || 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;
hasGLES3Impl = 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: hasGLES3Impl "+hasGLES3Impl);
}
}
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;
final HashMap _mappedProfiles = new HashMap(GL_PROFILE_LIST_ALL.length + 1 /* default */);
for(int i=0; i profileImpl "+profileImpl+" !!! not mapped ");
}
glProfile = new GLProfile(profile, _mglp, isHardwareRasterizer[0]);
}
_mappedProfiles.put(profile, glProfile);
if (DEBUG) {
System.err.println("GLProfile.init map "+glProfile+" on device "+device.getConnection());
}
if( null == defaultGLProfileHW && isHardwareRasterizer[0] ) {
defaultGLProfileHW=glProfile;
if (DEBUG) {
System.err.println("GLProfile.init map defaultHW "+glProfile+" on device "+device.getConnection());
}
} else if( null == defaultGLProfileAny ) {
defaultGLProfileAny=glProfile;
if (DEBUG) {
System.err.println("GLProfile.init map defaultAny "+glProfile+" on device "+device.getConnection());
}
}
} else {
if (DEBUG) {
System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getConnection());
}
}
}
if( null != defaultGLProfileHW ) {
_mappedProfiles.put(GL_DEFAULT, defaultGLProfileHW);
} else if( null != defaultGLProfileAny ) {
_mappedProfiles.put(GL_DEFAULT, defaultGLProfileAny);
}
setProfileMap(device, _mappedProfiles);
return _mappedProfiles.size() > 0;
}
/**
* Returns the profile implementation
*/
private static String computeProfileImpl(AbstractGraphicsDevice device, String profile, boolean desktopCtxUndef, boolean esCtxUndef, boolean isHardwareRasterizer[]) {
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 = hasGLES3Impl && ( esCtxUndef || GLContext.isGLES2Available(device, es2HardwareRasterizer) );
final boolean gles2HWAvailable = gles2Available && es2HardwareRasterizer[0] ;
final boolean es3HardwareRasterizer[] = new boolean[1];
final boolean gles3Available = hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, es3HardwareRasterizer) );
final boolean gles3HWAvailable = gles3Available && es3HardwareRasterizer[0] ;
if(hasGL234Impl) {
if(GLContext.isGL4Available(device, isHardwareRasterizer)) {
if( (!gles3HWAvailable && !gles2HWAvailable ) || isHardwareRasterizer[0] ) {
return GL4;
}
}
if(GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
if( (!gles3HWAvailable && !gles2HWAvailable ) || isHardwareRasterizer[0] ) {
return GL4bc;
}
}
if(GLContext.isGL3Available(device, isHardwareRasterizer)) {
if( (!gles3HWAvailable && !gles2HWAvailable ) || isHardwareRasterizer[0] ) {
return GL3;
}
}
if(GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
if( (!gles3HWAvailable && !gles2HWAvailable ) || isHardwareRasterizer[0] ) {
return GL3bc;
}
}
if(desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer)) {
if( (!gles3HWAvailable && !gles2HWAvailable ) || isHardwareRasterizer[0] ) {
return GL2;
}
}
}
if(gles3Available && ( !gles2HWAvailable || gles3HWAvailable ) ) {
isHardwareRasterizer[0] = es3HardwareRasterizer[0];
return GLES3;
}
if(gles2Available) {
isHardwareRasterizer[0] = es2HardwareRasterizer[0];
return GLES2;
}
} else if (GL4ES3.equals(profile)) {
final boolean gles3CompatAvail = GLContext.isGLES3CompatibleAvailable(device);
if( desktopCtxUndef || esCtxUndef || gles3CompatAvail ) {
final boolean es3HardwareRasterizer[] = new boolean[1];
final boolean gles3Available = hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, es3HardwareRasterizer) );
final boolean gles3HWAvailable = gles3Available && es3HardwareRasterizer[0] ;
if(hasGL234Impl) {
if(GLContext.isGL4Available(device, isHardwareRasterizer)) {
if(!gles3HWAvailable || isHardwareRasterizer[0]) {
return GL4;
}
}
if( GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
if(!gles3HWAvailable || isHardwareRasterizer[0]) {
return GL4bc;
}
}
if(GLContext.isGL3Available(device, isHardwareRasterizer)) {
if(!gles3HWAvailable || isHardwareRasterizer[0]) {
return GL3;
}
}
if( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
if(!gles3HWAvailable || isHardwareRasterizer[0]) {
return GL3bc;
}
}
}
if(gles3Available) {
isHardwareRasterizer[0] = es3HardwareRasterizer[0];
return GLES3;
}
}
} else if(GL2GL3.equals(profile)) {
if(hasGL234Impl) {
if( GLContext.isGL4bcAvailable(device, isHardwareRasterizer)) {
return GL4bc;
} else if( GLContext.isGL4Available(device, isHardwareRasterizer)) {
return GL4;
} else if( GLContext.isGL3bcAvailable(device, isHardwareRasterizer)) {
return GL3bc;
} else if( 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 desktopCtxUndef ? GL4bc : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_COMPAT);
} else if(GL4.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL4 : GLContext.getAvailableGLProfileName(device, 4, GLContext.CTX_PROFILE_CORE);
} else if(GL3bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL3bc : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_COMPAT);
} else if(GL3.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_CORE);
} else if(GL2.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device, isHardwareRasterizer))) {
return desktopCtxUndef ? GL2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_COMPAT);
} else if(GLES3.equals(profile) && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES3Available(device, isHardwareRasterizer))) {
return esCtxUndef ? GLES3 : GLContext.getAvailableGLProfileName(device, 3, GLContext.CTX_PROFILE_ES);
} else if(GLES2.equals(profile) && hasGLES3Impl && ( esCtxUndef || GLContext.isGLES2Available(device, isHardwareRasterizer))) {
return esCtxUndef ? GLES2 : GLContext.getAvailableGLProfileName(device, 2, GLContext.CTX_PROFILE_ES);
} else if(GLES1.equals(profile) && hasGLES1Impl && ( esCtxUndef || GLContext.isGLES1Available(device, isHardwareRasterizer))) {
return esCtxUndef ? GLES1 : GLContext.getAvailableGLProfileName(device, 1, GLContext.CTX_PROFILE_ES);
}
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;
}