diff options
author | Sven Gothel <[email protected]> | 2010-11-14 09:04:45 +0100 |
---|---|---|
committer | Sven Gothel <[email protected]> | 2010-11-14 09:04:45 +0100 |
commit | 83d3a3f2ea8dc328e621b3abbe671f46379c7e65 (patch) | |
tree | b7fafe2ef1610a6be0723316ae5bf5938b9f222d /src | |
parent | c3bfb82614e9fa0f8ea7169cd412a6f0c71973e0 (diff) |
JOGL: Complete eager and lazy mapping of GLProfiles in respect to multiple device.
AbstractGraphicsDevice's 'connection' and 'type' attribute is used as a unique key
to map GLProfiles and GLContext's major/profile -> major/minor/profile mapping.
Eager initialiaztion as well as lazy is supported to maintain a simple API.
This is currently tested on X11, where one app display NEWT/GL window and content
on the local and remote device.
See TestRemoteWindow01NEWT.java and TestRemoteGLWindows01NEWT.java
Diffstat (limited to 'src')
24 files changed, 1975 insertions, 664 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java index 86fbece4f..ee9d36147 100644 --- a/src/jogl/classes/com/jogamp/opengl/JoglVersion.java +++ b/src/jogl/classes/com/jogamp/opengl/JoglVersion.java @@ -57,8 +57,8 @@ public class JoglVersion extends JogampVersion { return jogampCommonVersionInfo; } - public StringBuffer getInfo(GL gl, StringBuffer sb) { - sb = super.getInfo(sb); + public StringBuffer toStringBuffer(GL gl, StringBuffer sb) { + sb = super.toStringBuffer(sb); getGLInfo(gl, sb); sb.append("-----------------------------------------------------------------------------------------------------"); @@ -67,12 +67,18 @@ public class JoglVersion extends JogampVersion { return sb; } + public String toString(GL gl) { + return toStringBuffer(gl, null).toString(); + } + public static StringBuffer getGLInfo(GL gl, StringBuffer sb) { if(null==sb) { sb = new StringBuffer(); } - sb.append(GLProfile.glAvailabilityToString()); + sb.append("Default Desktop ").append(GLProfile.getDefaultDesktopDevice().getConnection()).append(": ").append(GLProfile.glAvailabilityToString(GLProfile.getDefaultDesktopDevice())); + sb.append(Platform.getNewline()); + sb.append("Default EGL ").append(GLProfile.getDefaultEGLDevice().getConnection()).append(": ").append(GLProfile.glAvailabilityToString(GLProfile.getDefaultEGLDevice())); sb.append(Platform.getNewline()); sb.append("Swap Interval ").append(gl.getSwapInterval()); sb.append(Platform.getNewline()); @@ -93,7 +99,7 @@ public class JoglVersion extends JogampVersion { } public static void main(String args[]) { - System.err.println(JoglVersion.getInstance().getInfo(null)); + System.err.println(JoglVersion.getInstance()); } } diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLContextImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/GLContextImpl.java index ca689ed81..6c15a2d92 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLContextImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLContextImpl.java @@ -41,20 +41,37 @@ package com.jogamp.opengl.impl; import com.jogamp.common.os.DynamicLookupHelper; -import java.nio.*; -import java.util.*; - -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import com.jogamp.gluegen.runtime.*; -import com.jogamp.gluegen.runtime.opengl.*; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.gluegen.runtime.FunctionAddressResolver; +import com.jogamp.gluegen.runtime.ProcAddressTable; +import com.jogamp.gluegen.runtime.opengl.GLExtensionNames; +import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; +import java.util.StringTokenizer; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GL; +import javax.media.opengl.GLCapabilities; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; public abstract class GLContextImpl extends GLContext { - protected GLContextLock lock = new GLContextLock(); protected static final boolean DEBUG = Debug.debug("GLContext"); protected static final boolean VERBOSE = Debug.verbose(); + protected GLContextLock lock = new GLContextLock(); + + /** + * Context full qualified name: display_type + display_connection + major + minor + ctp. + * This is the key for all cached ProcAddressTables, etc, to support multi display/device setups. + */ + protected String contextFQN; + // Cache of the functions that are available to be called at the current // moment in time protected ExtensionAvailabilityCache extensionAvailability; @@ -73,15 +90,25 @@ public abstract class GLContextImpl extends GLContext { protected GL gl; + protected static final Object mappedContextTypeObjectLock; + protected static final HashMap mappedExtensionAvailabilityCache; + protected static final HashMap mappedGLProcAddress; + protected static final HashMap mappedGLXProcAddress; + + static { + mappedContextTypeObjectLock = new Object(); + mappedExtensionAvailabilityCache = new HashMap(); + mappedGLProcAddress = new HashMap(); + mappedGLXProcAddress = new HashMap(); + } + public GLContextImpl(GLDrawableImpl drawable, GLDrawableImpl drawableRead, GLContext shareWith) { - extensionAvailability = new ExtensionAvailabilityCache(this); + super(); + if (shareWith != null) { GLContextShareSet.registerSharing(this, shareWith); } GLContextShareSet.registerForBufferObjectSharing(shareWith, this); - // This must occur after the above calls into the - // GLContextShareSet, which set up state needed by the GL object - setGL(createGL(drawable.getGLProfile())); this.drawable = drawable; setGLDrawableRead(drawableRead); @@ -91,6 +118,32 @@ public abstract class GLContextImpl extends GLContext { this(drawable, null, shareWith); } + 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(); + } + + if (glStateTracker != null) { + glStateTracker.clearStates(false); + } + + extensionAvailability = null; + glProcAddressTable = null; + gl = null; + contextFQN = null; + + super.resetStates(); + } + public void setGLDrawableRead(GLDrawable read) { boolean lockHeld = lock.isHeld(); if(lockHeld) { @@ -185,24 +238,7 @@ public abstract class GLContextImpl extends GLContext { } } */ - - // 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(); - } - - if (glStateTracker != null) { - glStateTracker.clearStates(false); - } - if (contextHandle != 0) { int lockRes = drawable.lockSurface(); if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { @@ -220,6 +256,8 @@ public abstract class GLContextImpl extends GLContext { } finally { lock.unlock(); } + + resetStates(); } protected abstract void destroyImpl() throws GLException; @@ -364,6 +402,8 @@ public abstract class GLContextImpl extends GLContext { } boolean newCreated = false; if (!isCreated()) { + GLProfile.initProfiles( + getGLDrawable().getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice()); newCreated = createImpl(); // may throws exception if fails! if (DEBUG) { if(newCreated) { @@ -401,6 +441,8 @@ public abstract class GLContextImpl extends GLContext { * The implementation shall verify this context with a * <code>MakeContextCurrent</code> call.<br> * + * The implementation shall leave the context current.<br> + * * @param share the shared context or null * @param direct flag if direct is requested * @param ctxOptionFlags <code>ARB_create_context</code> related, see references below @@ -444,6 +486,8 @@ public abstract class GLContextImpl extends GLContext { * This method will also query all available native OpenGL context when first called,<br> * usually the first call should happen with the shared GLContext of the DrawableFactory.<br> * + * The implementation makes the context current, if successful<br> + * * @see #makeCurrentImpl * @see #create * @see #createContextARB @@ -454,14 +498,16 @@ public abstract class GLContextImpl extends GLContext { int major[], int minor[], int ctp[]) { AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); GLCapabilities glCaps = (GLCapabilities) config.getChosenCapabilities(); GLProfile glp = glCaps.getGLProfile(); if (DEBUG) { - System.err.println(getThreadName() + ": !!! createContextARB: mappedVersionsAvailableSet "+ mappedVersionsAvailableSet); + System.err.println(getThreadName() + ": !!! createContextARB: mappedVersionsAvailableSet("+device.getConnection()+"): "+ + GLContext.getAvailableGLVersionsSet(device)); } - mapGLVersions(); + mapGLVersions(device); int reqMajor; if(glp.isGL4()) { @@ -471,47 +517,44 @@ public abstract class GLContextImpl extends GLContext { } else /* if (glp.isGL2()) */ { reqMajor=2; } + boolean compat = glp.isGL2(); // incl GL3bc and GL4bc - - int key = compose8bit(reqMajor, compat?CTX_PROFILE_COMPAT:CTX_PROFILE_CORE, 0, 0); - int val; - synchronized(mappedVersionsAvailableLock) { - val = mappedVersionsAvailable.get( key ); - } + int _major[] = { 0 }; + int _minor[] = { 0 }; + int _ctp[] = { 0 }; long _ctx = 0; - if(val>0) { - int _major = getComposed8bit(val, 1); - int _minor = getComposed8bit(val, 2); - int _ctp = getComposed8bit(val, 3); - _ctx = createContextARBImpl(share, direct, _ctp, _major, _minor); + if( GLContext.getAvailableGLVersion(device, reqMajor, compat?CTX_PROFILE_COMPAT:CTX_PROFILE_CORE, + _major, _minor, _ctp)) { + _ctx = createContextARBImpl(share, direct, _ctp[0], _major[0], _minor[0]); if(0!=_ctx) { - setGLFunctionAvailability(true, _major, _minor, _ctp); + setGLFunctionAvailability(true, _major[0], _minor[0], _ctp[0]); } } return _ctx; } - private void mapGLVersions() { - if (!mappedVersionsAvailableSet) { - synchronized (mappedVersionsAvailableLock) { - if (!mappedVersionsAvailableSet) { - createContextARBMapVersionsAvailable(2, true /* compat */); // GL2 - createContextARBMapVersionsAvailable(3, true /* compat */); // GL3bc - createContextARBMapVersionsAvailable(3, false /* core */); // GL3 - createContextARBMapVersionsAvailable(4, true /* compat */); // GL4bc - createContextARBMapVersionsAvailable(4, false /* core */); // GL4 - mappedVersionsAvailableSet = true; - if (DEBUG) { - System.err.println(getThreadName() + ": !!! createContextARB: SET mappedVersionsAvailableSet " + mappedVersionsAvailableSet); - } - } + private final void mapGLVersions(AbstractGraphicsDevice device) { + if ( !GLContext.getAvailableGLVersionsSet(device) ) { + synchronized (GLContext.deviceVersionAvailable) { + createContextARBMapVersionsAvailable(4, false /* core */); // GL4 + createContextARBMapVersionsAvailable(4, true /* compat */); // GL4bc + createContextARBMapVersionsAvailable(3, false /* core */); // GL3 + createContextARBMapVersionsAvailable(3, true /* compat */); // GL3bc + createContextARBMapVersionsAvailable(2, true /* compat */); // GL2 + GLContext.setAvailableGLVersionsSet(device); + } + } else { + if(DEBUG) { + System.err.println(getThreadName() + ": no mapping, all versions set "+device.getConnection()); } } } private final void createContextARBMapVersionsAvailable(int reqMajor, boolean compat) { + resetStates(); + long _context; int reqProfile = compat ? CTX_PROFILE_COMPAT : CTX_PROFILE_CORE ; int ctp = CTX_IS_ARB_CREATED | CTX_PROFILE_CORE | CTX_OPTION_ANY; // default @@ -570,11 +613,14 @@ public abstract class GLContextImpl extends GLContext { } } if(0!=_context) { - destroyContextARBImpl(_context); - mapVersionAvailable(reqMajor, reqProfile, major[0], minor[0], ctp); + AbstractGraphicsDevice device = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + GLContext.mapAvailableGLVersion(device, reqMajor, reqProfile, major[0], minor[0], ctp); setGLFunctionAvailability(true, major[0], minor[0], ctp); + destroyContextARBImpl(_context); + resetStates(); if (DEBUG) { - System.err.println(getThreadName() + ": !!! createContextARBMapVersionsAvailable HAVE: "+getGLVersionAvailable(reqMajor, reqProfile)); + System.err.println(getThreadName() + ": !!! createContextARBMapVersionsAvailable HAVE: "+ + GLContext.getAvailableGLVersionAsString(device, reqMajor, reqProfile)); } } else if (DEBUG) { System.err.println(getThreadName() + ": !!! createContextARBMapVersionsAvailable NOPE: "+reqMajor+"."+reqProfile); @@ -615,7 +661,7 @@ public abstract class GLContextImpl extends GLContext { * If major==0 && minor == 0 : Use GL_VERSION * Otherwise .. don't touch .. */ - protected final void setContextVersion(int major, int minor, int ctp) { + private final void setContextVersion(int major, int minor, int ctp) { if (0==ctp) { throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp)); } @@ -643,6 +689,13 @@ public abstract class GLContextImpl extends GLContext { 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; + } ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, versionStr); return; } @@ -750,13 +803,17 @@ public abstract class GLContextImpl extends GLContext { * 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 + * and the extension cache is determined as well. * * @param force force the setting, even if is already being set. - * This might be usefull if you change the OpenGL implementation. + * This might be useful if you change the OpenGL implementation. * * @see #setContextVersion */ - protected void setGLFunctionAvailability(boolean force, int major, int minor, int ctp) { + + protected final void setGLFunctionAvailability(boolean force, int major, int minor, int ctp) { if(null!=this.gl && null!=glProcAddressTable && !force) { return; // already done and not forced } @@ -764,37 +821,34 @@ public abstract class GLContextImpl extends GLContext { setGL(createGL(getGLDrawable().getGLProfile())); } - updateGLProcAddressTable(major, minor, ctp); - } + AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); + contextFQN = getContextFQN(adevice, major, minor, ctp); + if (DEBUG) { + System.err.println(getThreadName() + ": !!! Context FQN: "+contextFQN); + } - /** - * Updates 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". - * - * @see #setContextVersion - */ - protected void updateGLProcAddressTable(int major, int minor, int ctp) { + updateGLXProcAddressTable(major, minor, ctp); + + // + // UpdateGLProcAddressTable functionality + // if(null==this.gl) { throw new GLException("setGLFunctionAvailability not called yet"); } - if (DEBUG) { - System.err.println(getThreadName() + ": !!! Initializing OpenGL extension address table for " + this); - } - int key = compose8bit(major, minor, ctp, 0); ProcAddressTable table = null; - synchronized(mappedProcAddressLock) { - table = (ProcAddressTable) mappedGLProcAddress.get( key ); + synchronized(mappedContextTypeObjectLock) { + table = (ProcAddressTable) mappedGLProcAddress.get( contextFQN ); if(null != table && !verifyInstance(gl.getGLProfile(), "ProcAddressTable", table)) { - throw new InternalError("GLContext GL ProcAddressTable mapped key("+major+","+minor+","+ctp+") -> "+ + throw new InternalError("GLContext GL ProcAddressTable mapped key("+contextFQN+") -> "+ table.getClass().getName()+" not matching "+gl.getGLProfile().getGLImplBaseClassName()); } } if(null != table) { glProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GL ProcAddressTable reusing key("+major+","+minor+","+ctp+") -> "+table.hashCode()); + System.err.println(getThreadName() + ": !!! GLContext GL ProcAddressTable reusing key("+contextFQN+") -> "+table.hashCode()); } } else { if (glProcAddressTable == null) { @@ -803,20 +857,52 @@ public abstract class GLContextImpl extends GLContext { new Object[] { new GLProcAddressResolver() } ); } resetProcAddressTable(getGLProcAddressTable()); - synchronized(mappedProcAddressLock) { - mappedGLProcAddress.put(key, getGLProcAddressTable()); + synchronized(mappedContextTypeObjectLock) { + mappedGLProcAddress.put(contextFQN, getGLProcAddressTable()); if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GL ProcAddressTable mapping key("+major+","+minor+","+ctp+") -> "+getGLProcAddressTable().hashCode()); + System.err.println(getThreadName() + ": !!! GLContext GL ProcAddressTable mapping key("+contextFQN+") -> "+getGLProcAddressTable().hashCode()); } } } + + // + // Set GL Version + // setContextVersion(major, minor, ctp); - extensionAvailability.reset(); + // + // Update ExtensionAvailabilityCache + // + ExtensionAvailabilityCache eCache; + synchronized(mappedContextTypeObjectLock) { + eCache = (ExtensionAvailabilityCache) mappedExtensionAvailabilityCache.get( contextFQN ); + } + if(null != eCache) { + extensionAvailability = eCache; + if(DEBUG) { + System.err.println(getThreadName() + ": !!! GLContext GL ExtensionAvailabilityCache reusing key("+contextFQN+") -> "+eCache.hashCode()); + } + } else { + if(null==extensionAvailability) { + extensionAvailability = new ExtensionAvailabilityCache(this); + } + extensionAvailability.reset(); + synchronized(mappedContextTypeObjectLock) { + mappedExtensionAvailabilityCache.put(contextFQN, extensionAvailability); + if(DEBUG) { + System.err.println(getThreadName() + ": !!! GLContext GL ExtensionAvailabilityCache mapping key("+contextFQN+") -> "+extensionAvailability.hashCode()); + } + } + } hasNativeES2Methods = isGLES2() || isExtensionAvailable("GL_ARB_ES2_compatibility") ; } + /** + * Updates the platform's 'GLX' function cache + */ + protected abstract void updateGLXProcAddressTable(int major, int minor, int ctp); + protected boolean hasNativeES2Methods = false; public final boolean hasNativeES2Methods() { return hasNativeES2Methods; } @@ -833,23 +919,26 @@ public abstract class GLContextImpl extends GLContext { * javax.media.opengl.GL#glPolygonOffset(float,float)} is available). */ public boolean isFunctionAvailable(String glFunctionName) { - if(isCreated()) { - // Check GL 1st (cached) - ProcAddressTable pTable = getGLProcAddressTable(); + // Check GL 1st (cached) + ProcAddressTable pTable = getGLProcAddressTable(); // null if ctx not created once + if(null!=pTable) { try { if(0!=pTable.getAddressFor(glFunctionName)) { return true; } } catch (Exception e) {} + } - // Check platform extensions 2nd (cached) - pTable = getPlatformExtProcAddressTable(); + // Check platform extensions 2nd (cached) - had to be enabled once + pTable = getPlatformExtProcAddressTable(); // null if ctx not created once + if(null!=pTable) { try { if(0!=pTable.getAddressFor(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); @@ -878,19 +967,31 @@ public abstract class GLContextImpl extends GLContext { * "GL_VERTEX_PROGRAM_ARB"). */ public boolean isExtensionAvailable(String glExtensionName) { - return extensionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName)); + if(null!=extensionAvailability) { + return extensionAvailability.isExtensionAvailable(mapToRealGLExtensionName(glExtensionName)); + } + return false; } public String getPlatformExtensionsString() { - return extensionAvailability.getPlatformExtensionsString(); + if(null!=extensionAvailability) { + return extensionAvailability.getPlatformExtensionsString(); + } + return null; } public String getGLExtensions() { - return extensionAvailability.getGLExtensions(); + if(null!=extensionAvailability) { + return extensionAvailability.getGLExtensions(); + } + return null; } public boolean isExtensionCacheInitialized() { - return extensionAvailability.isInitialized(); + if(null!=extensionAvailability) { + return extensionAvailability.isInitialized(); + } + return false; } /** Indicates which floating-point pbuffer implementation is in @@ -909,10 +1010,6 @@ public abstract class GLContextImpl extends GLContext { /** Only called for offscreen contexts; needed by glReadPixels */ public abstract int getOffscreenContextPixelDataType(); - protected static String getThreadName() { - return Thread.currentThread().getName(); - } - //---------------------------------------------------------------------- // Helpers for buffer object optimizations diff --git a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableFactoryImpl.java b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableFactoryImpl.java index 6837949d3..43f705e34 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/GLDrawableFactoryImpl.java @@ -225,8 +225,6 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { // // GLDrawableFactoryImpl details // - protected abstract GLDrawableImpl getSharedDrawable(); - protected abstract GLContextImpl getSharedContext(); protected void maybeDoSingleThreadedWorkaround(Runnable action) { if (Threading.isSingleThreaded() && diff --git a/src/jogl/classes/com/jogamp/opengl/impl/awt/Java2D.java b/src/jogl/classes/com/jogamp/opengl/impl/awt/Java2D.java index d8f83a5f7..5566a3a4a 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/awt/Java2D.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/awt/Java2D.java @@ -558,7 +558,7 @@ public class Java2D { } invokeWithOGLSharedContextCurrent(device.getDefaultConfiguration(), new Runnable() { public void run() { - j2dFBOShareContext = GLDrawableFactory.getFactory(GLProfile.getDefault()).createExternalGLContext(); + j2dFBOShareContext = GLDrawableFactory.getFactory(GLProfile.getDefault(GLProfile.getDefaultDesktopDevice())).createExternalGLContext(); } }); if (DEBUG) { diff --git a/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLContext.java b/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLContext.java index d8b5b78f2..d95a9e3ff 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLContext.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLContext.java @@ -192,22 +192,21 @@ public abstract class EGLContext extends GLContextImpl { return true; } - protected void updateGLProcAddressTable(int major, int minor, int ctp) { + protected final void updateGLXProcAddressTable(int major, int minor, int ctp) { if (DEBUG) { System.err.println(getThreadName() + ": !!! Initializing EGL extension address table"); } eglQueryStringInitialized = false; eglQueryStringAvailable = false; - int key = compose8bit(major, minor, ctp, 0); EGLExtProcAddressTable table = null; - synchronized(mappedProcAddressLock) { - table = (EGLExtProcAddressTable) mappedGLXProcAddress.get( key ); + synchronized(mappedContextTypeObjectLock) { + table = (EGLExtProcAddressTable) mappedGLXProcAddress.get( contextFQN ); } if(null != table) { eglExtProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext EGL ProcAddressTable reusing key("+major+","+minor+","+ctp+") -> "+table.hashCode()); + System.err.println(getThreadName() + ": !!! GLContext EGL ProcAddressTable reusing key("+contextFQN+") -> "+table.hashCode()); } } else { if (eglExtProcAddressTable == null) { @@ -216,14 +215,13 @@ public abstract class EGLContext extends GLContextImpl { eglExtProcAddressTable = new EGLExtProcAddressTable(new GLProcAddressResolver()); } resetProcAddressTable(getEGLExtProcAddressTable()); - synchronized(mappedProcAddressLock) { - mappedGLXProcAddress.put(key, getEGLExtProcAddressTable()); + synchronized(mappedContextTypeObjectLock) { + mappedGLXProcAddress.put(contextFQN, getEGLExtProcAddressTable()); if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext EGL ProcAddressTable mapping key("+major+","+minor+","+ctp+") -> "+getEGLExtProcAddressTable().hashCode()); + System.err.println(getThreadName() + ": !!! GLContext EGL ProcAddressTable mapping key("+contextFQN+") -> "+getEGLExtProcAddressTable().hashCode()); } } } - super.updateGLProcAddressTable(major, minor, ctp); } public synchronized String getPlatformExtensionsString() { diff --git a/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawableFactory.java index deb659ddf..6ebd3938a 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/egl/EGLDrawableFactory.java @@ -42,6 +42,8 @@ import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.*; import com.jogamp.opengl.impl.*; import com.jogamp.nativewindow.impl.ProxySurface; +import java.util.HashMap; +import javax.media.nativewindow.egl.EGLGraphicsDevice; public class EGLDrawableFactory extends GLDrawableFactoryImpl { @@ -93,6 +95,39 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { public EGLDrawableFactory() { super(); + /** FIXME: + * find out the Windows semantics of a device connection {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection()} + * to actually use multiple devices. + */ + defaultDevice = new EGLGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION); + } + + static class SharedResource { + private EGLDrawable drawable; + private EGLContext context; + + SharedResource(EGLDrawable draw, EGLContext ctx) { + drawable = draw; + context = ctx; + } + } + HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + EGLGraphicsDevice defaultDevice; + + public final AbstractGraphicsDevice getDefaultDevice() { + return defaultDevice; + } + + public final boolean getIsDeviceCompatible(AbstractGraphicsDevice device) { + if(device instanceof EGLGraphicsDevice) { + return true; + } + return false; + } + + protected final GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device) { + // FIXME: not implemented .. needs a dummy EGL surface + return null; } public GLDynamicLookupHelper getGLDynamicLookupHelper(int esProfile) { @@ -112,8 +147,6 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } protected void shutdownInstance() {} - protected final GLDrawableImpl getSharedDrawable() { return null; } - protected final GLContextImpl getSharedContext() { return null; } protected GLDrawableImpl createOnscreenDrawableImpl(NativeSurface target) { if (target == null) { @@ -141,7 +174,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } protected GLContext createExternalGLContextImpl() { - AbstractGraphicsScreen absScreen = DefaultGraphicsScreen.createScreenDevice(0); + AbstractGraphicsScreen absScreen = DefaultGraphicsScreen.createScreenDevice(AbstractGraphicsDevice.EXTERNAL_CONNECTION, 0); return new EGLExternalContext(absScreen); } diff --git a/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLContext.java index f9934fe20..e9b543721 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLContext.java @@ -224,19 +224,18 @@ public abstract class MacOSXCGLContext extends GLContextImpl } } - protected void updateGLProcAddressTable(int major, int minor, int ctp) { + protected final void updateGLXProcAddressTable(int major, int minor, int ctp) { if (DEBUG) { System.err.println(getThreadName() + ": !!! Initializing CGL extension address table"); } - int key = compose8bit(major, minor, ctp, 0); CGLExtProcAddressTable table = null; - synchronized(mappedProcAddressLock) { - table = (CGLExtProcAddressTable) mappedGLXProcAddress.get( key ); + synchronized(mappedContextTypeObjectLock) { + table = (CGLExtProcAddressTable) mappedGLXProcAddress.get( contextFQN ); } if(null != table) { cglExtProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext CGL ProcAddressTable reusing key("+major+","+minor+","+ctp+") -> "+table.hashCode()); + System.err.println(getThreadName() + ": !!! GLContext CGL ProcAddressTable reusing key("+contextFQN+") -> "+table.hashCode()); } } else { if (cglExtProcAddressTable == null) { @@ -245,14 +244,13 @@ public abstract class MacOSXCGLContext extends GLContextImpl cglExtProcAddressTable = new CGLExtProcAddressTable(new GLProcAddressResolver()); } resetProcAddressTable(getCGLExtProcAddressTable()); - synchronized(mappedProcAddressLock) { - mappedGLXProcAddress.put(key, getCGLExtProcAddressTable()); + synchronized(mappedContextTypeObjectLock) { + mappedGLXProcAddress.put(contextFQN, getCGLExtProcAddressTable()); if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext CGL ProcAddressTable mapping key("+major+","+minor+","+ctp+") -> "+getCGLExtProcAddressTable().hashCode()); + System.err.println(getThreadName() + ": !!! GLContext CGL ProcAddressTable mapping key("+contextFQN+") -> "+getCGLExtProcAddressTable().hashCode()); } } } - super.updateGLProcAddressTable(major, minor, ctp); } public String getPlatformExtensionsString() diff --git a/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLDrawableFactory.java index 9a02e55ee..f41b68d31 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -47,6 +47,8 @@ import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.*; import com.jogamp.opengl.impl.*; import com.jogamp.nativewindow.impl.ProxySurface; +import java.util.HashMap; +import javax.media.nativewindow.macosx.MacOSXGraphicsDevice; public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { private static final DesktopGLDynamicLookupHelper macOSXCGLDynamicLookupHelper; @@ -83,11 +85,43 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { null, getClass().getClassLoader()); } catch (JogampRuntimeException jre) { /* n/a .. */ } } + + /** FIXME: + * find out the Windows semantics of a device connection {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection()} + * to actually use multiple devices. + */ + defaultDevice = new MacOSXGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION); + } + + static class SharedResource { + private MacOSXCGLDrawable drawable; + private MacOSXCGLContext context; + + SharedResource(MacOSXCGLDrawable draw, MacOSXCGLContext ctx) { + drawable = draw; + context = ctx; + } + } + HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + MacOSXGraphicsDevice defaultDevice; + + public final AbstractGraphicsDevice getDefaultDevice() { + return defaultDevice; + } + + public final boolean getIsDeviceCompatible(AbstractGraphicsDevice device) { + if(device instanceof MacOSXGraphicsDevice) { + return true; + } + return false; + } + + protected final GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device) { + // FIXME: not implemented .. needs a dummy OSX surface + return null; } protected void shutdownInstance() {} - protected final GLDrawableImpl getSharedDrawable() { return null; } - protected final GLContextImpl getSharedContext() { return null; } protected GLDrawableImpl createOnscreenDrawableImpl(NativeSurface target) { if (target == null) { diff --git a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLContext.java b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLContext.java index c9a12c85b..7be597dcc 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLContext.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLContext.java @@ -49,12 +49,12 @@ import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; public class WindowsWGLContext extends GLContextImpl { + private static final Map/*<String, String>*/ functionNameMap; + private static final Map/*<String, String>*/ extensionNameMap; private boolean wglGetExtensionsStringEXTInitialized; private boolean wglGetExtensionsStringEXTAvailable; private boolean wglMakeContextCurrentInitialized; private boolean wglMakeContextCurrentAvailable; - private static final Map/*<String, String>*/ functionNameMap; - private static final Map/*<String, String>*/ extensionNameMap; private WGLExt wglExt; // Table that holds the addresses of the native C-language entry points for // WGL extension functions. @@ -80,6 +80,15 @@ public class WindowsWGLContext extends GLContextImpl { GLContext shareWith) { this(drawable, null, shareWith); } + + protected void resetState() { + wglGetExtensionsStringEXTInitialized=false; + wglGetExtensionsStringEXTAvailable=false; + wglMakeContextCurrentInitialized=false; + wglMakeContextCurrentAvailable=false; + // no inner state wglExt=null; + wglExtProcAddressTable=null; + } public Object getPlatformGLExtensions() { return getWGLExt(); @@ -120,17 +129,20 @@ public class WindowsWGLContext extends GLContextImpl { protected Map/*<String, String>*/ getExtensionNameMap() { return extensionNameMap; } protected void destroyContextARBImpl(long context) { - WGL.wglMakeCurrent(0, 0); + wglMakeContextCurrent(0, 0, 0); WGL.wglDeleteContext(context); } protected long createContextARBImpl(long share, boolean direct, int ctp, int major, int minor) { WindowsWGLDrawableFactory factory = (WindowsWGLDrawableFactory)drawable.getFactoryImpl(); + AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); + WindowsWGLContext sharedContext = (WindowsWGLContext) factory.getOrCreateSharedContextImpl(device); WGLExt wglExt; - if(null==factory.getSharedContext()) { + if(null==sharedContext) { wglExt = getWGLExt(); } else { - wglExt = ((WindowsWGLContext)factory.getSharedContext()).getWGLExt(); + wglExt = sharedContext.getWGLExt(); } boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; @@ -171,22 +183,32 @@ public class WindowsWGLContext extends GLContextImpl { } } - ctx = wglExt.wglCreateContextAttribsARB(drawable.getHandle(), share, attribs, 0); - if(DEBUG) { - System.err.println("WindowsWGLContext.createContextARB success: "+(0!=ctx)+" - "+getGLVersion(major, minor, ctp, "@creation")+", bwdCompat "+ctBwdCompat+", fwdCompat "+ctFwdCompat); + try { + ctx = wglExt.wglCreateContextAttribsARB(drawable.getHandle(), share, attribs, 0); + } catch (RuntimeException re) { + if(DEBUG) { + Throwable t = new Throwable("Info: WindowWGLContext.createContextARBImpl wglCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation"), re); + t.printStackTrace(); + } } + if(0!=ctx) { - // In contrast to GLX no verification with a drawable binding, ie default framebuffer, is necessary, - // if no 3.2 is available creation fails already! - // Nevertheless .. we do it .. - if (!WGL.wglMakeCurrent(drawable.getHandle(), ctx)) { + if (!wglMakeContextCurrent(drawable.getHandle(), drawableRead.getHandle(), ctx)) { if(DEBUG) { System.err.println("WindowsWGLContext.createContextARB couldn't make current "+getGLVersion(major, minor, ctp, "@creation")); } WGL.wglMakeCurrent(0, 0); WGL.wglDeleteContext(ctx); ctx = 0; + } else { + if (DEBUG) { + System.err.println(getThreadName() + ": createContextARBImpl: OK "+getGLVersion(major, minor, ctp, "@creation")+", share "+share+", direct "+direct+", hasSharedContext "+(null!=sharedContext)); + } + // the following is issued by the caller 'GLContextImpl.createContextARB()' + // setGLFunctionAvailability(true, major, minor, ctp); } + } else if (DEBUG) { + System.err.println(getThreadName() + ": createContextARBImpl: NO "+getGLVersion(major, minor, ctp, "@creation")); } return ctx; } @@ -197,6 +219,9 @@ public class WindowsWGLContext extends GLContextImpl { */ protected boolean createImpl() { WindowsWGLDrawableFactory factory = (WindowsWGLDrawableFactory)drawable.getFactoryImpl(); + AbstractGraphicsConfiguration config = drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); + WindowsWGLContext sharedContext = (WindowsWGLContext) factory.getOrCreateSharedContextImpl(device); GLCapabilities glCaps = drawable.getChosenGLCapabilities(); // Windows can set up sharing of display lists after creation time @@ -215,7 +240,7 @@ public class WindowsWGLContext extends GLContextImpl { boolean createContextARBTried = false; // utilize the shared context's GLXExt in case it was using the ARB method and it already exists - if( null!=factory.getSharedContext() && factory.getSharedContext().isCreatedWithARBMethod() ) { + if( null!=sharedContext && sharedContext.isCreatedWithARBMethod() ) { contextHandle = createContextARB(share, true, major, minor, ctp); createContextARBTried = true; if (DEBUG && 0!=contextHandle) { @@ -235,16 +260,24 @@ public class WindowsWGLContext extends GLContextImpl { throw new GLException("Error making temp context current: 0x" + toHexString(temp_ctx) + ", werr: 0x"+Integer.toHexString(GDI.GetLastError())); } setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + boolean isCreateContextAttribsARBAvailable = isFunctionAvailable("wglCreateContextAttribsARB"); WGL.wglMakeCurrent(0, 0); // release temp context - if( !createContextARBTried && - isFunctionAvailable("wglCreateContextAttribsARB") && - isExtensionAvailable("WGL_ARB_create_context") ) { - // initial ARB context creation - contextHandle = createContextARB(share, true, major, minor, ctp); - createContextARBTried=true; - if (DEBUG && 0!=contextHandle) { - System.err.println(getThreadName() + ": createImpl: OK (ARB, initial) share "+share); + if( !createContextARBTried) { + if(isCreateContextAttribsARBAvailable && + isExtensionAvailable("WGL_ARB_create_context") ) { + // initial ARB context creation + contextHandle = createContextARB(share, true, major, minor, ctp); + createContextARBTried=true; + if (DEBUG) { + if(0!=contextHandle) { + System.err.println(getThreadName() + ": createContextImpl: OK (ARB, initial) share "+share); + } else { + System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - creation failed - share "+share); + } + } + } else if (DEBUG) { + System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - extension not available - share "+share); } } } @@ -328,7 +361,7 @@ public class WindowsWGLContext extends GLContextImpl { } } - protected void updateGLProcAddressTable(int major, int minor, int ctp) { + protected final void updateGLXProcAddressTable(int major, int minor, int ctp) { if (DEBUG) { System.err.println(getThreadName() + ": !!! Initializing WGL extension address table for " + this); } @@ -337,15 +370,14 @@ public class WindowsWGLContext extends GLContextImpl { wglMakeContextCurrentInitialized=false; wglMakeContextCurrentAvailable=false; - int key = compose8bit(major, minor, ctp, 0); WGLExtProcAddressTable table = null; - synchronized(mappedProcAddressLock) { - table = (WGLExtProcAddressTable) mappedGLXProcAddress.get( key ); + synchronized(mappedContextTypeObjectLock) { + table = (WGLExtProcAddressTable) mappedGLXProcAddress.get( contextFQN ); } if(null != table) { wglExtProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext WGL ProcAddressTable reusing key("+major+","+minor+","+ctp+") -> "+table.hashCode()); + System.err.println(getThreadName() + ": !!! GLContext WGL ProcAddressTable reusing key("+contextFQN+") -> "+table.hashCode()); } } else { if (wglExtProcAddressTable == null) { @@ -354,14 +386,13 @@ public class WindowsWGLContext extends GLContextImpl { wglExtProcAddressTable = new WGLExtProcAddressTable(new GLProcAddressResolver()); } resetProcAddressTable(getWGLExtProcAddressTable()); - synchronized(mappedProcAddressLock) { - mappedGLXProcAddress.put(key, getWGLExtProcAddressTable()); + synchronized(mappedContextTypeObjectLock) { + mappedGLXProcAddress.put(contextFQN, getWGLExtProcAddressTable()); if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext WGL ProcAddressTable mapping key("+major+","+minor+","+ctp+") -> "+getWGLExtProcAddressTable().hashCode()); + System.err.println(getThreadName() + ": !!! GLContext WGL ProcAddressTable mapping key("+contextFQN+") -> "+getWGLExtProcAddressTable().hashCode()); } } } - super.updateGLProcAddressTable(major, minor, ctp); } public String getPlatformExtensionsString() { diff --git a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLDrawableFactory.java index cea176b1f..f8405961f 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLDrawableFactory.java @@ -48,6 +48,7 @@ import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.*; import com.jogamp.opengl.impl.*; import com.jogamp.nativewindow.impl.ProxySurface; +import javax.media.nativewindow.windows.WindowsGraphicsDevice; public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { private static final boolean VERBOSE = Debug.verbose(); @@ -86,57 +87,112 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } catch (JogampRuntimeException jre) { /* n/a .. */ } } - NativeWindowFactory.getDefaultToolkitLock().lock(); // OK - try { - sharedDrawable = new WindowsDummyWGLDrawable(this, null); - WindowsWGLContext ctx = (WindowsWGLContext) sharedDrawable.createContext(null); - ctx.makeCurrent(); - canCreateGLPbuffer = ctx.getGL().isExtensionAvailable("GL_ARB_pbuffer"); - ctx.release(); - sharedContext = ctx; - } catch (Throwable t) { - throw new GLException("WindowsWGLDrawableFactory - Could not initialize shared resources", t); - } finally { - NativeWindowFactory.getDefaultToolkitLock().unlock(); // OK - } - if(null==sharedContext) { - throw new GLException("WindowsWGLDrawableFactory - Shared Context is null"); - } - if (DEBUG) { - System.err.println("!!! SharedContext: "+sharedContext+", pbuffer supported "+canCreateGLPbuffer); - } + /** FIXME: + * find out the Windows semantics of a device connection {@link javax.media.nativewindow.AbstractGraphicsDevice#getConnection()} + * to actually use multiple devices. + */ + defaultDevice = new WindowsGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION); } - WindowsDummyWGLDrawable sharedDrawable=null; - WindowsWGLContext sharedContext=null; - boolean canCreateGLPbuffer = false; + static class SharedResource { + private WindowsDummyWGLDrawable drawable; + private WindowsWGLContext context; + private boolean canCreateGLPbuffer; + + SharedResource(WindowsDummyWGLDrawable draw, WindowsWGLContext ctx, boolean canPbuffer) { + drawable = draw; + context = ctx; + canCreateGLPbuffer = canPbuffer; + } + } + HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + WindowsGraphicsDevice defaultDevice; + + public final AbstractGraphicsDevice getDefaultDevice() { + return defaultDevice; + } - protected final GLDrawableImpl getSharedDrawable() { - return sharedDrawable; + public final boolean getIsDeviceCompatible(AbstractGraphicsDevice device) { + if(device instanceof WindowsGraphicsDevice) { + return true; + } + return false; } - protected final GLContextImpl getSharedContext() { - return sharedContext; + HashSet devicesTried = new HashSet(); + private final boolean getDeviceTried(String connection) { + synchronized(devicesTried) { + return devicesTried.contains(connection); + } + } + private final void addDeviceTried(String connection) { + synchronized(devicesTried) { + devicesTried.add(connection); + } + } + + protected final GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device) { + String connection = device.getConnection(); + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(connection); + } + if(null==sr && !getDeviceTried(connection)) { + addDeviceTried(connection); + NativeWindowFactory.getDefaultToolkitLock().lock(); // OK + try { + WindowsDummyWGLDrawable sharedDrawable = new WindowsDummyWGLDrawable(this, null); + WindowsWGLContext ctx = (WindowsWGLContext) sharedDrawable.createContext(null); + ctx.makeCurrent(); + boolean canCreateGLPbuffer = ctx.getGL().isExtensionAvailable("GL_ARB_pbuffer"); + ctx.release(); + sr = new SharedResource(sharedDrawable, ctx, canCreateGLPbuffer); + synchronized(sharedMap) { + sharedMap.put(device.getConnection(), sr); + } + if (DEBUG) { + System.err.println("!!! SharedContext: "+ctx+", pbuffer supported "+canCreateGLPbuffer); + } + + } catch (Throwable t) { + throw new GLException("WindowsWGLDrawableFactory - Could not initialize shared resources", t); + } finally { + NativeWindowFactory.getDefaultToolkitLock().unlock(); // OK + } + } + if(null!=sr) { + return sr.context; + } + return null; } protected void shutdownInstance() { - if (DEBUG) { + if (DEBUG) { + Exception e = new Exception("Debug"); + e.printStackTrace(); + } + Collection/*<SharedResource>*/ sharedResources = sharedMap.values(); + for(Iterator iter=sharedResources.iterator(); iter.hasNext(); ) { + SharedResource sr = (SharedResource) iter.next(); + + if (DEBUG) { System.err.println("!!! Shutdown Shared:"); - System.err.println("!!! CTX : "+sharedContext); - System.err.println("!!! Drawable: "+sharedDrawable); - Exception e = new Exception("Debug"); - e.printStackTrace(); - } - // don't free native resources from this point on, - // since we might be in a critical shutdown hook sequence - if(null!=sharedContext) { - // may cause deadlock: sharedContext.destroy(); // implies release, if current - sharedContext=null; - } - if(null!=sharedDrawable) { - // may cause deadlock: sharedDrawable.destroy(); - sharedDrawable=null; - } + System.err.println("!!! Drawable: "+sr.drawable); + System.err.println("!!! CTX : "+sr.context); + } + + if (null != sr.context) { + // may cause JVM SIGSEGV: sharedContext.destroy(); + sr.context = null; + } + + if (null != sr.drawable) { + // may cause JVM SIGSEGV: sharedDrawable.destroy(); + sr.drawable = null; + } + + } + sharedMap.clear(); } protected GLDrawableImpl createOnscreenDrawableImpl(NativeSurface target) { @@ -154,13 +210,29 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } public boolean canCreateGLPbuffer(AbstractGraphicsDevice device) { - return canCreateGLPbuffer; + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(device.getConnection()); + } + if(null!=sr) { + return sr.canCreateGLPbuffer; + } + return false; } protected GLDrawableImpl createGLPbufferDrawableImpl(final NativeSurface target) { if (target == null) { throw new IllegalArgumentException("Null target"); } + final AbstractGraphicsDevice device = target.getGraphicsConfiguration().getNativeGraphicsConfiguration().getScreen().getDevice(); + + final SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(device.getConnection()); + } + if(null==sr) { + return null; + } final List returnList = new ArrayList(); Runnable r = new Runnable() { public void run() { @@ -168,16 +240,16 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { if (lastContext != null) { lastContext.release(); } - synchronized(WindowsWGLDrawableFactory.this.sharedContext) { - WindowsWGLDrawableFactory.this.sharedContext.makeCurrent(); + synchronized(sr.context) { + sr.context.makeCurrent(); try { - WGLExt wglExt = WindowsWGLDrawableFactory.this.sharedContext.getWGLExt(); + WGLExt wglExt = sr.context.getWGLExt(); GLDrawableImpl pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target, - WindowsWGLDrawableFactory.this.sharedDrawable, + sr.drawable, wglExt); returnList.add(pbufferDrawable); } finally { - WindowsWGLDrawableFactory.this.sharedContext.release(); + sr.context.release(); if (lastContext != null) { lastContext.makeCurrent(); } diff --git a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfiguration.java index 8744b7a37..619034da4 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -65,7 +65,7 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio throw new GLException("Invalid pixelformat id "+pfdID); } if(null==glp) { - glp = GLProfile.getDefault(); + glp = GLProfile.getDefault(screen.getDevice()); } PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(); if (GDI.DescribePixelFormat(hdc, pfdID, pfd.size(), pfd) == 0) { diff --git a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index 317751725..d34467fb1 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -98,8 +98,13 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilitiesChooser objects"); } - boolean choosenBywGLPixelFormat = false; WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); + WindowsWGLContext sharedContext = (WindowsWGLContext) factory.getOrCreateSharedContextImpl(device); + if(null==sharedContext) { + throw new InternalError("SharedContext is null: "+device); + } + boolean choosenBywGLPixelFormat = false; GLCapabilities capabilities = (GLCapabilities) config.getRequestedCapabilities(); boolean onscreen = capabilities.isOnscreen(); boolean usePBuffer = capabilities.isPBuffer(); @@ -138,12 +143,11 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio // Produce a recommended pixel format selection for the GLCapabilitiesChooser. // Use wglChoosePixelFormatARB if user requested multisampling and if we have it available int recommendedPixelFormat = pixelFormat; // 1-based pixel format - boolean gotAvailableCaps = false; - synchronized(factory.sharedContext) { - factory.sharedContext.makeCurrent(); + boolean gotAvailableCaps = false; + synchronized(sharedContext) { + sharedContext.makeCurrent(); try { - WGLExt wglExt = factory.sharedContext.getWGLExt(); - + WGLExt wglExt = sharedContext.getWGLExt(); boolean haveWGLChoosePixelFormatARB = false; if (wglExt != null) { haveWGLChoosePixelFormatARB = wglExt.isExtensionAvailable("WGL_ARB_pixel_format"); @@ -198,7 +202,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GraphicsConfiguratio } } } finally { - factory.sharedContext.release(); + sharedContext.release(); } } // synchronized(factory.sharedContext) diff --git a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXContext.java b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXContext.java index d80da1dd4..75e523cbc 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXContext.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXContext.java @@ -48,14 +48,15 @@ import com.jogamp.opengl.impl.*; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; import com.jogamp.nativewindow.impl.x11.X11Util; +import javax.media.nativewindow.x11.X11GraphicsDevice; public abstract class X11GLXContext extends GLContextImpl { protected static final boolean TRACE_CONTEXT_CURRENT = false; // true; - private boolean glXQueryExtensionsStringInitialized; - private boolean glXQueryExtensionsStringAvailable; private static final Map/*<String, String>*/ functionNameMap; private static final Map/*<String, String>*/ extensionNameMap; + private boolean glXQueryExtensionsStringInitialized; + private boolean glXQueryExtensionsStringAvailable; private GLXExt glXExt; // Table that holds the addresses of the native C-language entry points for // GLX extension functions. @@ -87,6 +88,15 @@ public abstract class X11GLXContext extends GLContextImpl { this(drawable, null, shareWith); } + protected void resetState() { + glXQueryExtensionsStringInitialized=false; + glXQueryExtensionsStringAvailable=false; + // no inner state glXExt=null; + glXExtProcAddressTable = null; + hasSwapIntervalSGI = 0; + isDirect = false; + } + public final ProcAddressTable getPlatformExtProcAddressTable() { return getGLXExtProcAddressTable(); } @@ -145,13 +155,15 @@ public abstract class X11GLXContext extends GLContextImpl { X11GLXDrawableFactory factory = (X11GLXDrawableFactory)drawable.getFactoryImpl(); X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - long display = config.getScreen().getDevice().getHandle(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); + X11GLXContext sharedContext = (X11GLXContext) factory.getOrCreateSharedContextImpl(device); + long display = device.getHandle(); GLXExt glXExt; - if(null==factory.getSharedContext()) { + if(null==sharedContext) { glXExt = getGLXExt(); } else { - glXExt = ((X11GLXContext)factory.getSharedContext()).getGLXExt(); + glXExt = sharedContext.getGLXExt(); } boolean ctBwdCompat = 0 != ( CTX_PROFILE_COMPAT & ctp ) ; @@ -192,7 +204,11 @@ public abstract class X11GLXContext extends GLContextImpl { } try { + // critical path, a remote display might not support this command, + // hence we need to catch the X11 Error within this block. + X11Util.XSync(display, false); ctx = glXExt.glXCreateContextAttribsARB(display, config.getFBConfig(), share, direct, attribs, 0); + X11Util.XSync(display, false); } catch (RuntimeException re) { if(DEBUG) { Throwable t = new Throwable("Info: X11GLXContext.createContextARBImpl glXCreateContextAttribsARB failed with "+getGLVersion(major, minor, ctp, "@creation"), re); @@ -210,8 +226,10 @@ public abstract class X11GLXContext extends GLContextImpl { ctx = 0; } else { if (DEBUG) { - System.err.println(getThreadName() + ": createContextARBImpl: OK "+getGLVersion(major, minor, ctp, "@creation")+", share "+share+", direct "+direct+", hasSharedContext "+(null!=factory.getSharedContext())); + System.err.println(getThreadName() + ": createContextARBImpl: OK "+getGLVersion(major, minor, ctp, "@creation")+", share "+share+", direct "+direct+", hasSharedContext "+(null!=sharedContext)); } + // the following is issued by the caller 'GLContextImpl.createContextARB()' + // setGLFunctionAvailability(true, major, minor, ctp); } } else if (DEBUG) { System.err.println(getThreadName() + ": createContextARBImpl: NO "+getGLVersion(major, minor, ctp, "@creation")); @@ -236,7 +254,9 @@ public abstract class X11GLXContext extends GLContextImpl { X11GLXDrawableFactory factory = (X11GLXDrawableFactory)drawable.getFactoryImpl(); X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - long display = config.getScreen().getDevice().getHandle(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); + X11GLXContext sharedContext = (X11GLXContext) factory.getOrCreateSharedContextImpl(device); + long display = device.getHandle(); X11GLXContext other = (X11GLXContext) GLContextShareSet.getShareContext(this); long share = 0; @@ -250,7 +270,7 @@ public abstract class X11GLXContext extends GLContextImpl { GLCapabilities glCaps = (GLCapabilities) config.getChosenCapabilities(); GLProfile glp = glCaps.getGLProfile(); - isVendorATI = factory.isVendorATI(); + isVendorATI = factory.isVendorATI(device); if(config.getFBConfigID()<0) { // not able to use FBConfig @@ -278,7 +298,7 @@ public abstract class X11GLXContext extends GLContextImpl { boolean createContextARBTried = false; // utilize the shared context's GLXExt in case it was using the ARB method and it already exists - if(null!=factory.getSharedContext() && factory.getSharedContext().isCreatedWithARBMethod()) { + if(null!=sharedContext && sharedContext.isCreatedWithARBMethod()) { contextHandle = createContextARB(share, direct, major, minor, ctp); createContextARBTried = true; if (DEBUG && 0!=contextHandle) { @@ -298,16 +318,24 @@ public abstract class X11GLXContext extends GLContextImpl { throw new GLException("Error making temp context(1) current: display "+toHexString(display)+", context "+toHexString(temp_ctx)+", drawable "+drawable); } setGLFunctionAvailability(true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); // use GL_VERSION + boolean isCreateContextAttribsARBAvailable = isFunctionAvailable("glXCreateContextAttribsARB"); glXMakeContextCurrent(display, 0, 0, 0); // release temp context - if( !createContextARBTried && - isFunctionAvailable("glXCreateContextAttribsARB") && - isExtensionAvailable("GLX_ARB_create_context") ) { - // initial ARB context creation - contextHandle = createContextARB(share, direct, major, minor, ctp); - createContextARBTried=true; - if (DEBUG && 0!=contextHandle) { - System.err.println(getThreadName() + ": createContextImpl: OK (ARB, initial) share "+share); + if( !createContextARBTried ) { + if ( isCreateContextAttribsARBAvailable && + isExtensionAvailable("GLX_ARB_create_context") ) { + // initial ARB context creation + contextHandle = createContextARB(share, direct, major, minor, ctp); + createContextARBTried=true; + if (DEBUG) { + if(0!=contextHandle) { + System.err.println(getThreadName() + ": createContextImpl: OK (ARB, initial) share "+share); + } else { + System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - creation failed - share "+share); + } + } + } else if (DEBUG) { + System.err.println(getThreadName() + ": createContextImpl: NOT OK (ARB, initial) - extension not available - share "+share); } } } @@ -407,36 +435,34 @@ public abstract class X11GLXContext extends GLContextImpl { // Should check for X errors and raise GLException } - protected void updateGLProcAddressTable(int major, int minor, int ctp) { + protected final void updateGLXProcAddressTable(int major, int minor, int ctp) { if (DEBUG) { System.err.println(getThreadName() + ": !!! Initializing GLX extension address table"); } glXQueryExtensionsStringInitialized = false; glXQueryExtensionsStringAvailable = false; - int key = compose8bit(major, minor, ctp, 0); GLXExtProcAddressTable table = null; - synchronized(mappedProcAddressLock) { - table = (GLXExtProcAddressTable) mappedGLXProcAddress.get( key ); + synchronized(mappedContextTypeObjectLock) { + table = (GLXExtProcAddressTable) mappedGLXProcAddress.get( contextFQN ); } if(null != table) { glXExtProcAddressTable = table; if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GLX ProcAddressTable reusing key("+major+","+minor+","+ctp+") -> "+table.hashCode()); + System.err.println(getThreadName() + ": !!! GLContext GLX ProcAddressTable reusing key("+contextFQN+") -> "+table.hashCode()); } } else { if (glXExtProcAddressTable == null) { glXExtProcAddressTable = new GLXExtProcAddressTable(new GLProcAddressResolver()); } resetProcAddressTable(getGLXExtProcAddressTable()); - synchronized(mappedProcAddressLock) { - mappedGLXProcAddress.put(key, getGLXExtProcAddressTable()); + synchronized(mappedContextTypeObjectLock) { + mappedGLXProcAddress.put(contextFQN, getGLXExtProcAddressTable()); if(DEBUG) { - System.err.println(getThreadName() + ": !!! GLContext GLX ProcAddressTable mapping key("+major+","+minor+","+ctp+") -> "+getGLXExtProcAddressTable().hashCode()); + System.err.println(getThreadName() + ": !!! GLContext GLX ProcAddressTable mapping key("+contextFQN+") -> "+getGLXExtProcAddressTable().hashCode()); } } } - super.updateGLProcAddressTable(major, minor, ctp); } public synchronized String getPlatformExtensionsString() { @@ -476,8 +502,8 @@ public abstract class X11GLXContext extends GLContextImpl { try { hasSwapIntervalSGI = glXExt.isExtensionAvailable("GLX_SGI_swap_control")?1:-1; } catch (Throwable t) { hasSwapIntervalSGI=1; } - } - if (hasSwapIntervalSGI>0) { + } + if (hasSwapIntervalSGI>0) { try { if( 0 == glXExt.glXSwapIntervalSGI(interval) ) { currentSwapInterval = interval; diff --git a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java index 5b5c07a61..7efbc6ed7 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXDrawableFactory.java @@ -47,6 +47,10 @@ import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.*; import com.jogamp.nativewindow.impl.ProxySurface; import com.jogamp.nativewindow.impl.x11.*; +import java.util.Collection; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { @@ -83,43 +87,61 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } catch (JogampRuntimeException jre) { /* n/a .. */ } } + defaultDevice = new X11GraphicsDevice(X11Util.getNullDisplayName()); + // Init shared resources via own thread // Will be released via ShutdownHook sharedResourcesRunner = new SharedResourcesRunner(); sharedResourcesThread = new Thread(sharedResourcesRunner, Thread.currentThread().getName()+"-SharedResourcesRunner"); sharedResourcesThread.setDaemon(true); // Allow JVM to exit, even if this one is running sharedResourcesThread.start(); - sharedResourcesRunner.waitUntilInitialized(); - - if (DEBUG) { - System.err.println("!!! Vendor: "+vendorName+", ATI: "+isVendorATI+", NV: "+isVendorNVIDIA); - System.err.println("!!! SharedScreen: "+sharedScreen); - System.err.println("!!! SharedContext: "+sharedContext); - } } class SharedResourcesRunner implements Runnable { - boolean initialized = false; + boolean ready = false; boolean released = false; boolean shouldRelease = false; + String initConnection = null; + SharedResource result = null; - public void waitUntilInitialized() { + public final void initializeAndWait(String connection) { + // wait until thread becomes ready to init new device, + // pass the device and release the sync + String threadName = Thread.currentThread().getName(); + if (DEBUG) { + System.err.println(threadName+ " initializeAndWait START: "+connection); + } synchronized (this) { - while (!this.initialized) { + while (!ready) { try { this.wait(); - } catch (InterruptedException ex) { - } + } catch (InterruptedException ex) { } + } + if (DEBUG) { + System.err.println(threadName+ " initializeAndWait set command: "+connection); + } + initConnection = connection; + this.notifyAll(); + + // wait until thread has initialized the device + while (!ready || null != initConnection) { + try { + this.wait(); + } catch (InterruptedException ex) { } + } + if (DEBUG) { + System.err.println(threadName+ " initializeAndWait done: "+connection); } } + // done } - public void releaseAndWait() { + public final void releaseAndWait() { synchronized (this) { - this.shouldRelease = true; + shouldRelease = true; this.notifyAll(); - while (!this.released) { + while (!released) { try { this.wait(); } catch (InterruptedException ex) { @@ -128,118 +150,244 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } } - public void run() { + public final void run() { String threadName = Thread.currentThread().getName(); - X11GraphicsDevice sharedDevice; + synchronized (this) { if (DEBUG) { - System.err.println(threadName+ " initializing START"); + System.err.println(threadName+ " STARTED -> ready"); } - sharedDevice = new X11GraphicsDevice(X11Util.createDisplay(null)); - sharedDevice.setCloseDisplay(true); - X11Util.lockDefaultToolkit(sharedDevice.getHandle()); // OK - try { - vendorName = GLXUtil.getVendorName(sharedDevice.getHandle()); - isVendorATI = GLXUtil.isVendorATI(vendorName); - isVendorNVIDIA = GLXUtil.isVendorNVIDIA(vendorName); - sharedScreen = new X11GraphicsScreen(sharedDevice, 0); - sharedDrawable = new X11DummyGLXDrawable(sharedScreen, X11GLXDrawableFactory.this, GLProfile.getDefault()); - if (null == sharedScreen || null == sharedDrawable) { - throw new GLException("Couldn't init shared screen(" + sharedScreen + ")/drawable(" + sharedDrawable + ")"); - } + + while (!shouldRelease) { try { - X11GLXContext ctx = (X11GLXContext) sharedDrawable.createContext(null); - ctx.makeCurrent(); - ctx.release(); - sharedContext = ctx; - } catch (Throwable t) { - throw new GLException("X11GLXDrawableFactory - Could not initialize shared resources", t); - } - if (null == sharedContext) { - throw new GLException("X11GLXDrawableFactory - Shared Context is null"); + // wait for stop or init + ready = true; + this.wait(); + } catch (InterruptedException ex) { } + ready = false; + + if(!shouldRelease && null!=initConnection) { + if (DEBUG) { + System.err.println(threadName+ " create Shared for: "+initConnection); + } + SharedResource sr = createSharedResource(initConnection); + if(null!=sr) { + synchronized(sharedMap) { + sharedMap.put(initConnection, sr); + } + } + if (DEBUG) { + String msg = "Info: (" + threadName + ") initializedSharedResource for device connection: "+initConnection+" -> ready"; + System.err.println(msg); + Throwable t = new Throwable(msg); + t.printStackTrace(); + } } - } finally { - X11Util.unlockDefaultToolkit(sharedDevice.getHandle()); // OK + initConnection = null; + notifyAll(); } if (DEBUG) { - System.err.println(threadName+ " initializing DONE"); + System.err.println(threadName+ " release START"); + } + + releaseSharedResources(); + + if (DEBUG) { + System.err.println(threadName+ " release END"); } - initialized = true; + + released = true; + ready = false; notifyAll(); } - - if (DEBUG) { - System.err.println(threadName+ " release WAIT"); + } + + private final SharedResource createSharedResource(String connection) { + X11GraphicsDevice sharedDevice = new X11GraphicsDevice(X11Util.createDisplay(connection)); + sharedDevice.setCloseDisplay(true); + X11Util.lockDefaultToolkit(sharedDevice.getHandle()); // OK + try { + String vendorName = GLXUtil.getVendorName(sharedDevice.getHandle()); + X11GraphicsScreen sharedScreen = new X11GraphicsScreen(sharedDevice, 0); + X11DummyGLXDrawable sharedDrawable = new X11DummyGLXDrawable(sharedScreen, X11GLXDrawableFactory.this, GLProfile.getDefault(sharedDevice)); + if (null == sharedScreen || null == sharedDrawable) { + throw new GLException("Couldn't init shared screen(" + sharedScreen + ")/drawable(" + sharedDrawable + ")"); + } + X11GLXContext sharedContext; + try { + X11GLXContext ctx = (X11GLXContext) sharedDrawable.createContext(null); + ctx.makeCurrent(); + ctx.release(); + sharedContext = ctx; + } catch (Throwable t) { + throw new GLException("X11GLXDrawableFactory - Could not initialize shared resources", t); + } + if (null == sharedContext) { + throw new GLException("X11GLXDrawableFactory - Shared Context is null"); + } + if (DEBUG) { + System.err.println("!!! SharedDevice: "+sharedDevice); + System.err.println("!!! SharedScreen: "+sharedScreen); + System.err.println("!!! SharedContext: "+sharedContext); + System.err.println("!!! Vendor: "+vendorName); + } + return new SharedResource(sharedDevice, sharedScreen, sharedDrawable, sharedContext, vendorName); + } finally { + X11Util.unlockDefaultToolkit(sharedDevice.getHandle()); // OK } + } + + private final void releaseSharedResources() { + Collection/*<SharedResource>*/ sharedResources = sharedMap.values(); + for(Iterator iter=sharedResources.iterator(); iter.hasNext(); ) { + SharedResource sr = (SharedResource) iter.next(); - synchronized(this) { - while (!this.shouldRelease) { - try { - this.wait(); - } catch (InterruptedException ex) { - } - } if (DEBUG) { - System.err.println(threadName+ " release START"); + System.err.println("!!! Shutdown Shared:"); + System.err.println("!!! Device : "+sr.device); + System.err.println("!!! Screen : "+sr.screen); + System.err.println("!!! Drawable: "+sr.drawable); + System.err.println("!!! CTX : "+sr.context); } - if (null != sharedContext) { + + if (null != sr.context) { // may cause JVM SIGSEGV: sharedContext.destroy(); - sharedContext = null; + sr.context = null; } - if (null != sharedDrawable) { + if (null != sr.drawable) { // may cause JVM SIGSEGV: sharedDrawable.destroy(); - sharedDrawable = null; - } - - if (null != sharedScreen) { - sharedScreen = null; + sr.drawable = null; } - if (null != sharedDevice) { - sharedDevice.close(); - sharedDevice = null; + if (null != sr.screen) { + sr.screen = null; } - if (DEBUG) { - System.err.println(threadName+ " release END"); + if (null != sr.device) { + sr.device.close(); + sr.device=null; } - released = true; - notifyAll(); } + sharedMap.clear(); } } - Thread sharedResourcesThread = null; SharedResourcesRunner sharedResourcesRunner=null; - private X11GraphicsScreen sharedScreen=null; - private X11DummyGLXDrawable sharedDrawable=null; - private X11GLXContext sharedContext=null; - private String vendorName; - private boolean isVendorATI; - private boolean isVendorNVIDIA; - - protected String getVendorName() { return vendorName; } - protected boolean isVendorATI() { return isVendorATI; } - protected boolean isVendorNVIDIA() { return isVendorNVIDIA; } - - protected final GLDrawableImpl getSharedDrawable() { - return sharedDrawable; + + static class SharedResource { + private X11GraphicsDevice device; + private X11GraphicsScreen screen; + private X11DummyGLXDrawable drawable; + private X11GLXContext context; + private String vendorName; + private boolean isVendorATI; + private boolean isVendorNVIDIA; + + SharedResource(X11GraphicsDevice dev, X11GraphicsScreen scrn, X11DummyGLXDrawable draw, X11GLXContext ctx, String vendor) { + device = dev; + screen = scrn; + drawable = draw; + context = ctx; + vendorName = vendor; + isVendorATI = GLXUtil.isVendorATI(vendorName); + isVendorNVIDIA = GLXUtil.isVendorNVIDIA(vendorName); + } } + HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + SharedResource defaultShare; + X11GraphicsDevice defaultDevice; - protected final GLContextImpl getSharedContext() { - return sharedContext; + public final AbstractGraphicsDevice getDefaultDevice() { + return defaultDevice; } - protected void shutdownInstance() { + public final boolean getIsDeviceCompatible(AbstractGraphicsDevice device) { + if(device instanceof X11GraphicsDevice) { + return true; + } + return false; + } + + HashSet devicesTried = new HashSet(); + private final boolean getDeviceTried(String connection) { + synchronized(devicesTried) { + return devicesTried.contains(connection); + } + } + private final void addDeviceTried(String connection) { + synchronized(devicesTried) { + devicesTried.add(connection); + } + } + + protected final GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device) { + String connection = device.getConnection(); + boolean deviceTried = getDeviceTried(connection); + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(connection); + } + if (DEBUG) { - System.err.println("!!! Shutdown Shared:"); - System.err.println("!!! CTX : "+sharedContext); - System.err.println("!!! Drawable: "+sharedDrawable); - System.err.println("!!! Screen : "+sharedScreen); + System.err.println("getOrCreateSharedContext() "+connection+": has shared "+(null!=sr)+", already tried "+deviceTried); } + if(null==sr && !deviceTried) { + if (DEBUG) { + System.err.println("getOrCreateSharedContext() "+connection+": trying"); + } + addDeviceTried(connection); + sharedResourcesRunner.initializeAndWait(connection); + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(connection); + } + if(DEBUG) { + Throwable t = new Throwable("getOrCreateSharedContextImpl() "+connection+": done"); + t.printStackTrace(); + } + } + if(null!=sr) { + return sr.context; + } + return null; + } + + protected final String getVendorName(AbstractGraphicsDevice device) { + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(device.getConnection()); + } + if(null!=sr) { + return sr.vendorName; + } + return null; + } + + protected final boolean isVendorATI(AbstractGraphicsDevice device) { + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(device.getConnection()); + } + if(null!=sr) { + return sr.isVendorATI; + } + return false; + } + + protected final boolean isVendorNVIDIA(AbstractGraphicsDevice device) { + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(device.getConnection()); + } + if(null!=sr) { + return sr.isVendorNVIDIA; + } + return false; + } + + protected void shutdownInstance() { sharedResourcesRunner.releaseAndWait(); X11Util.shutdown( true, DEBUG ); @@ -268,7 +416,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { protected final boolean glxVersionGreaterEqualThan(AbstractGraphicsDevice device, int majorReq, int minorReq) { if (!glxVersionsQueried) { if(null == device) { - device = (X11GraphicsDevice) sharedScreen.getDevice(); + device = (X11GraphicsDevice) defaultShare.screen.getDevice(); } if(null == device) { throw new GLException("FIXME: No AbstractGraphicsDevice (passed or shared-device"); @@ -302,19 +450,26 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { GLDrawableImpl pbufferDrawable; + AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + AbstractGraphicsDevice device = config.getScreen().getDevice(); + /** * Due to the ATI Bug https://bugzilla.mozilla.org/show_bug.cgi?id=486277, * we need to have a context current on the same Display to create a PBuffer. * The dummy context shall also use the same Display, * since switching Display in this regard is another ATI bug. */ - if( isVendorATI() && null == GLContext.getCurrent() ) { - synchronized(sharedContext) { - sharedContext.makeCurrent(); + SharedResource sr; + synchronized(sharedMap) { + sr = (SharedResource) sharedMap.get(device.getConnection()); + } + if( sr.isVendorATI && null == GLContext.getCurrent() ) { + synchronized(sr.context) { + sr.context.makeCurrent(); try { pbufferDrawable = new X11PbufferGLXDrawable(this, target); } finally { - sharedContext.release(); + sr.context.release(); } } } else { @@ -325,7 +480,8 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(GLCapabilities capabilities, GLCapabilitiesChooser chooser, int width, int height) { - ProxySurface ns = new ProxySurface(X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capabilities, chooser, sharedScreen)); + ProxySurface ns = new ProxySurface( + X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capabilities, chooser, defaultShare.screen)); if(ns != null) { ns.setSize(width, height); } @@ -364,7 +520,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { return gammaRampLength; } - long display = sharedScreen.getDevice().getHandle(); + long display = defaultShare.screen.getDevice().getHandle(); int[] size = new int[1]; boolean res = X11Util.XF86VidModeGetGammaRampSize(display, @@ -385,7 +541,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData[i] = (short) (ramp[i] * 65535); } - long display = sharedScreen.getDevice().getHandle(); + long display = defaultShare.screen.getDevice().getHandle(); boolean res = X11Util.XF86VidModeSetGammaRamp(display, X11Util.DefaultScreen(display), rampData.length, @@ -407,7 +563,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData.position(2 * size); rampData.limit(3 * size); ShortBuffer blueRampData = rampData.slice(); - long display = sharedScreen.getDevice().getHandle(); + long display = defaultShare.screen.getDevice().getHandle(); boolean res = X11Util.XF86VidModeGetGammaRamp(display, X11Util.DefaultScreen(display), size, @@ -438,7 +594,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { rampData.position(2 * size); rampData.limit(3 * size); ShortBuffer blueRampData = rampData.slice(); - long display = sharedScreen.getDevice().getHandle(); + long display = defaultShare.screen.getDevice().getHandle(); X11Util.XF86VidModeSetGammaRamp(display, X11Util.DefaultScreen(display), size, diff --git a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXGraphicsConfiguration.java index 3df9ee541..8661fba5e 100644 --- a/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXGraphicsConfiguration.java +++ b/src/jogl/classes/com/jogamp/opengl/impl/x11/glx/X11GLXGraphicsConfiguration.java @@ -67,7 +67,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem throw new GLException("FBConfig null of "+toHexString(fbcfgID)); } if(null==glp) { - glp = GLProfile.getDefault(); + glp = GLProfile.getDefault(x11Screen.getDevice()); } GLCapabilities caps = GLXFBConfig2GLCapabilities(glp, display, fbcfg, true, true, true, GLXUtil.isMultisampleAvailable(display)); if(null==caps) { diff --git a/src/jogl/classes/javax/media/opengl/GLCapabilities.java b/src/jogl/classes/javax/media/opengl/GLCapabilities.java index 4368add3f..d48b95c79 100644 --- a/src/jogl/classes/javax/media/opengl/GLCapabilities.java +++ b/src/jogl/classes/javax/media/opengl/GLCapabilities.java @@ -81,7 +81,7 @@ public class GLCapabilities extends Capabilities implements Cloneable { * @param glp GLProfile, or null for the default GLProfile */ public GLCapabilities(GLProfile glp) { - glProfile = (null!=glp)?glp:GLProfile.getDefault(); + glProfile = (null!=glp)?glp:GLProfile.getDefault(GLProfile.getDefaultDevice()); } public Object clone() { diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 2f63d5c8e..34ac8e93b 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -40,9 +40,10 @@ package javax.media.opengl; +import com.jogamp.opengl.impl.Debug; import java.util.HashMap; -import com.jogamp.common.util.IntIntHashMap; -import com.jogamp.common.util.IntObjectHashMap; +import java.util.HashSet; +import javax.media.nativewindow.AbstractGraphicsDevice; /** Abstraction for an OpenGL rendering context. In order to perform OpenGL rendering, a context must be "made current" on the current @@ -56,8 +57,9 @@ import com.jogamp.common.util.IntObjectHashMap; process is handled by the implementation, and the GLContext abstraction provides a stable object which clients can use to refer to a given context. */ - public abstract class GLContext { + protected static final boolean DEBUG0 = Debug.debug("GLContext"); + /** Indicates that the context was not made current during the last call to {@link #makeCurrent makeCurrent}. */ public static final int CONTEXT_NOT_CURRENT = 0; /** Indicates that the context was made current during the last call to {@link #makeCurrent makeCurrent}. */ @@ -65,6 +67,21 @@ public abstract class GLContext { /** Indicates that a newly-created context was made current during the last call to {@link #makeCurrent makeCurrent}. */ public static final int CONTEXT_CURRENT_NEW = 2; + /** <code>ARB_create_context</code> related: created via ARB_create_context */ + protected static final int CTX_IS_ARB_CREATED = 1 << 0; + /** <code>ARB_create_context</code> related: compatibility profile */ + protected static final int CTX_PROFILE_COMPAT = 1 << 1; + /** <code>ARB_create_context</code> related: core profile */ + protected static final int CTX_PROFILE_CORE = 1 << 2; + /** <code>ARB_create_context</code> related: ES profile */ + protected static final int CTX_PROFILE_ES = 1 << 3; + /** <code>ARB_create_context</code> related: flag forward compatible */ + protected static final int CTX_OPTION_FORWARD = 1 << 4; + /** <code>ARB_create_context</code> related: not flag forward compatible */ + protected static final int CTX_OPTION_ANY = 1 << 5; + /** <code>ARB_create_context</code> related: flag debug */ + protected static final int CTX_OPTION_DEBUG = 1 << 6; + private static ThreadLocal currentContext = new ThreadLocal(); private HashMap/*<int, Object>*/ attachedObjects = new HashMap(); @@ -72,6 +89,26 @@ public abstract class GLContext { /** The underlying native OpenGL context */ protected long contextHandle; + protected GLContext() { + resetStates(); + } + + protected int ctxMajorVersion; + protected int ctxMinorVersion; + protected int ctxOptions; + protected String ctxVersionString; + + protected void resetStates() { + ctxMajorVersion=-1; + ctxMinorVersion=-1; + ctxOptions=0; + ctxVersionString=null; + if(null!=attachedObjects) { + attachedObjects.clear(); + } + contextHandle=0; + } + /** * Returns the GLDrawable to which this context may be used to * draw. @@ -225,6 +262,8 @@ public abstract class GLContext { /** * Returns the GL pipeline object for this GLContext. + * + * @return the aggregated GL instance, or null if this context was not yet made current. */ public abstract GL getGL(); @@ -371,41 +410,26 @@ public abstract class GLContext { return ctxVersionString; } - protected int ctxMajorVersion=-1; - protected int ctxMinorVersion=-1; - protected int ctxOptions=0; - protected String ctxVersionString=null; - - /** <code>ARB_create_context</code> related: created via ARB_create_context */ - protected static final int CTX_IS_ARB_CREATED = 1 << 0; - /** <code>ARB_create_context</code> related: compatibility profile */ - protected static final int CTX_PROFILE_COMPAT = 1 << 1; - /** <code>ARB_create_context</code> related: core profile */ - protected static final int CTX_PROFILE_CORE = 1 << 2; - /** <code>ARB_create_context</code> related: ES profile */ - protected static final int CTX_PROFILE_ES = 1 << 3; - /** <code>ARB_create_context</code> related: flag forward compatible */ - protected static final int CTX_OPTION_FORWARD = 1 << 4; - /** <code>ARB_create_context</code> related: not flag forward compatible */ - protected static final int CTX_OPTION_ANY = 1 << 5; - /** <code>ARB_create_context</code> related: flag debug */ - protected static final int CTX_OPTION_DEBUG = 1 << 6; - - public final boolean isGL4bc() { - return ctxMajorVersion>=4 && 0!=(ctxOptions & CTX_PROFILE_COMPAT); + return ctxMajorVersion>=4 && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & CTX_PROFILE_COMPAT); } public final boolean isGL4() { - return ctxMajorVersion>=4 && 0!=(ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); + return ctxMajorVersion>=4 && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); } public final boolean isGL3bc() { - return ctxMajorVersion>=3 && 0!=(ctxOptions & CTX_PROFILE_COMPAT); + return ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) + && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & CTX_PROFILE_COMPAT); } public final boolean isGL3() { - return ctxMajorVersion>=3 && 0!=(ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); + return ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) + && 0 != (ctxOptions & CTX_IS_ARB_CREATED) + && 0 != (ctxOptions & (CTX_PROFILE_COMPAT|CTX_PROFILE_CORE)); } public final boolean isGL2() { @@ -483,18 +507,122 @@ public abstract class GLContext { return true; } + protected static int compose8bit(int one, int two, int three, int four) { + return ( ( one & 0x000000FF ) << 24 ) | + ( ( two & 0x000000FF ) << 16 ) | + ( ( three & 0x000000FF ) << 8 ) | + ( ( four & 0x000000FF ) ) ; + } + + protected static int getComposed8bit(int bits32, int which ) { + switch (which) { + case 1: return ( bits32 & 0xFF000000 ) >> 24 ; + case 2: return ( bits32 & 0x00FF0000 ) >> 16 ; + case 3: return ( bits32 & 0x0000FF00 ) >> 8 ; + case 4: return ( bits32 & 0xFF0000FF ) ; + } + throw new GLException("argument which out of range: "+which); + } + + protected static String composed8BitToString(int bits32, boolean hex1, boolean hex2, boolean hex3, boolean hex4) { + int a = getComposed8bit(bits32, 1); + int b = getComposed8bit(bits32, 2); + int c = getComposed8bit(bits32, 3); + int d = getComposed8bit(bits32, 4); + return "["+toString(a, hex1)+", "+toString(b, hex2)+", "+toString(c, hex3)+", "+toString(d, hex4)+"]"; + } + + private static void validateProfileBits(int bits, String argName) { + int num = 0; + if( 0 != ( CTX_PROFILE_COMPAT & bits ) ) { num++; } + if( 0 != ( CTX_PROFILE_CORE & bits ) ) { num++; } + if( 0 != ( CTX_PROFILE_ES & bits ) ) { num++; } + if(1!=num) { + throw new GLException("Internal Error: "+argName+": 1 != num-profiles: "+num); + } + } + + // + // version mapping + // + /** - * @param major Key Value either 1, 2, 3 or 4 + * @see #getDeviceVersionAvailableKey(javax.media.nativewindow.AbstractGraphicsDevice, int, int) + */ + protected static /*final*/ HashMap/*<DeviceVersionAvailableKey, Integer>*/ deviceVersionAvailable = new HashMap(); + + /** + * @see #getUniqueDeviceString(javax.media.nativewindow.AbstractGraphicsDevice) + */ + private static /*final*/ HashSet/*<UniqueDeviceString>*/ deviceVersionsAvailableSet = new HashSet(); + + protected static String getContextFQN(AbstractGraphicsDevice device, int major, int minor, int ctp) { + return getUniqueDeviceString(device) + "-" + toHexString(compose8bit(major, minor, ctp, 0)); + } + + protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { + return getUniqueDeviceString(device) + "-" + toHexString(compose8bit(major, profile, 0, 0)); + } + + protected static String getUniqueDeviceString(AbstractGraphicsDevice device) { + return device.getType() + "_" + device.getConnection() ; + } + + protected static boolean getAvailableGLVersionsSet(AbstractGraphicsDevice device) { + synchronized ( deviceVersionsAvailableSet ) { + return deviceVersionsAvailableSet.contains(getUniqueDeviceString(device)); + } + } + + protected static void setAvailableGLVersionsSet(AbstractGraphicsDevice device) { + synchronized ( deviceVersionsAvailableSet ) { + String devKey = getUniqueDeviceString(device); + if ( deviceVersionsAvailableSet.contains(devKey) ) { + throw new InternalError("Already set: "+devKey); + } + deviceVersionsAvailableSet.add(devKey); + if (DEBUG0) { + String msg = getThreadName() + ": !!! createContextARB: SET mappedVersionsAvailableSet "+devKey; + Throwable t = new Throwable(msg); + t.printStackTrace(); + // System.err.println(msg); + } + } + } + + /** + * Called by {@link com.jogamp.opengl.impl.GLContextImpl#createContextARBMapVersionsAvailable} not intended to be used by + * implementations. However, if {@link #createContextARB} is not being used within + * {@link javax.media.opengl.GLDrawableFactory#getOrCreateSharedContext(javax.media.nativewindow.AbstractGraphicsDevice)}, + * GLProfile has to map the available versions. + * + * @param reqMajor Key Value either 1, 2, 3 or 4 * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} + * @return the old mapped value + * + * @see #createContextARBMapVersionsAvailable */ - public static final String getGLVersionAvailable(int major, int profile) { - int _major[] = { 0 }; - int _minor[] = { 0 }; - int _ctp[] = { 0 }; - if(getGLVersionAvailable(major, profile, _major, _minor, _ctp)) { - return getGLVersion(_major[0], _minor[0], _ctp[0], null); + protected static Integer mapAvailableGLVersion(AbstractGraphicsDevice device, + int reqMajor, int profile, int resMajor, int resMinor, int resCtp) + { + validateProfileBits(profile, "profile"); + validateProfileBits(resCtp, "resCtp"); + + String key = getDeviceVersionAvailableKey(device, reqMajor, profile); + Integer val = new Integer(compose8bit(resMajor, resMinor, resCtp, 0)); + synchronized(deviceVersionAvailable) { + val = (Integer) deviceVersionAvailable.put( key, val ); } - return null; + return val; + } + + protected static Integer getAvailableGLVersion(AbstractGraphicsDevice device, int reqMajor, int profile) { + String key = getDeviceVersionAvailableKey(device, reqMajor, profile); + Integer val; + synchronized(deviceVersionAvailable) { + val = (Integer) deviceVersionAvailable.get( key ); + } + return val; } /** @@ -504,15 +632,16 @@ public abstract class GLContext { * @param minor if not null, returns the used minor version * @param ctp if not null, returns the used context profile */ - public static final boolean getGLVersionAvailable(int reqMajor, int reqProfile, int[] major, int minor[], int ctp[]) { - int key = compose8bit(reqMajor, reqProfile, 0, 0); - int val; - synchronized(mappedVersionsAvailableLock) { - val = mappedVersionsAvailable.get( key ); - } - if(val<=0) { + protected static boolean getAvailableGLVersion(AbstractGraphicsDevice device, + int reqMajor, int reqProfile, int[] major, int minor[], int ctp[]) { + + Integer valI = getAvailableGLVersion(device, reqMajor, reqProfile); + if(null==valI) { return false; } + + int val = valI.intValue(); + if(null!=major) { major[0] = getComposed8bit(val, 1); } @@ -529,14 +658,51 @@ public abstract class GLContext { * @param major Key Value either 1, 2, 3 or 4 * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} */ - public static final boolean isGLVersionAvailable(int major, int profile) { - return getGLVersionAvailable(major, profile, null, null, null); + public static boolean isGLVersionAvailable(AbstractGraphicsDevice device, int major, int profile) { + return null != getAvailableGLVersion(device, major, profile); + } + + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); + } + + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); + } + + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); + } + + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); + } + + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); + } + + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); + } + + public static boolean isGL2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT); + } + + /** + * @param major Key Value either 1, 2, 3 or 4 + * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} + */ + public static String getAvailableGLVersionAsString(AbstractGraphicsDevice device, int major, int profile) { + int _major[] = { 0 }; + int _minor[] = { 0 }; + int _ctp[] = { 0 }; + if(getAvailableGLVersion(device, major, profile, _major, _minor, _ctp)) { + return getGLVersion(_major[0], _minor[0], _ctp[0], null); + } + return null; } - public static final boolean isGL4bcAvailable() { return isGLVersionAvailable(4, CTX_PROFILE_COMPAT); } - public static final boolean isGL4Available() { return isGLVersionAvailable(4, CTX_PROFILE_CORE); } - public static final boolean isGL3bcAvailable() { return isGLVersionAvailable(3, CTX_PROFILE_COMPAT); } - public static final boolean isGL3Available() { return isGLVersionAvailable(3, CTX_PROFILE_CORE); } - public static final boolean isGL2Available() { return isGLVersionAvailable(2, CTX_PROFILE_COMPAT); } public static String getGLVersion(int major, int minor, int ctp, String gl_version) { boolean needColon = false; @@ -560,83 +726,6 @@ public abstract class GLContext { return sb.toString(); } - protected static final Object mappedVersionsAvailableLock; - protected static final IntIntHashMap mappedVersionsAvailable; - protected static volatile boolean mappedVersionsAvailableSet; - - protected static final Object mappedProcAddressLock; - protected static final IntObjectHashMap mappedGLProcAddress; - protected static final IntObjectHashMap mappedGLXProcAddress; - - static { - mappedVersionsAvailableLock = new Object(); - mappedVersionsAvailableSet = false; - mappedVersionsAvailable = new IntIntHashMap(); - mappedVersionsAvailable.setKeyNotFoundValue(-1); - mappedProcAddressLock = new Object(); - mappedGLProcAddress = new IntObjectHashMap(); - mappedGLProcAddress.setKeyNotFoundValue(null); - mappedGLXProcAddress = new IntObjectHashMap(); - mappedGLXProcAddress.setKeyNotFoundValue(null); - } - - private static void validateProfileBits(int bits, String argName) { - int num = 0; - if( 0 != ( CTX_PROFILE_COMPAT & bits ) ) { num++; } - if( 0 != ( CTX_PROFILE_CORE & bits ) ) { num++; } - if( 0 != ( CTX_PROFILE_ES & bits ) ) { num++; } - if(1!=num) { - throw new GLException("Internal Error: "+argName+": 1 != num-profiles: "+num); - } - } - - /** - * Called by {@link GLContextImpl#createContextARBMapVersionsAvailable} not intendet to be used by - * implementations. However, if {@link #createContextARB} is not being used within the - * {@link GLDrawableImpl} constructor, GLProfile has to map the available versions. - * - * @param reqMajor Key Value either 1, 2, 3 or 4 - * @param profile Key Value either {@link #CTX_PROFILE_COMPAT}, {@link #CTX_PROFILE_CORE} or {@link #CTX_PROFILE_ES} - - * @see #createContextARBMapVersionsAvailable - */ - protected static void mapVersionAvailable(int reqMajor, int profile, int resMajor, int resMinor, int resCtp) - { - validateProfileBits(profile, "profile"); - validateProfileBits(resCtp, "resCtp"); - - int key = compose8bit(reqMajor, profile, 0, 0); - int val = compose8bit(resMajor, resMinor, resCtp, 0); - synchronized(mappedVersionsAvailableLock) { - mappedVersionsAvailable.put( key, val ); - } - } - - protected static int compose8bit(int one, int two, int three, int four) { - return ( ( one & 0x000000FF ) << 24 ) | - ( ( two & 0x000000FF ) << 16 ) | - ( ( three & 0x000000FF ) << 8 ) | - ( ( four & 0x000000FF ) ) ; - } - - protected static int getComposed8bit(int bits32, int which ) { - switch (which) { - case 1: return ( bits32 & 0xFF000000 ) >> 24 ; - case 2: return ( bits32 & 0x00FF0000 ) >> 16 ; - case 3: return ( bits32 & 0x0000FF00 ) >> 8 ; - case 4: return ( bits32 & 0xFF0000FF ) ; - } - throw new GLException("argument which out of range: "+which); - } - - protected static String composed8BitToString(int bits32, boolean hex1, boolean hex2, boolean hex3, boolean hex4) { - int a = getComposed8bit(bits32, 1); - int b = getComposed8bit(bits32, 2); - int c = getComposed8bit(bits32, 3); - int d = getComposed8bit(bits32, 4); - return "["+toString(a, hex1)+", "+toString(b, hex2)+", "+toString(c, hex3)+", "+toString(d, hex4)+"]"; - } - protected static String toString(int val, boolean hex) { if(hex) { return "0x" + Integer.toHexString(val); @@ -662,6 +751,10 @@ public abstract class GLContext { } return needColon; } + + protected static String getThreadName() { + return Thread.currentThread().getName(); + } } diff --git a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java index d1bdcdda1..f6dce1c9c 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawableFactory.java @@ -47,6 +47,7 @@ import com.jogamp.common.util.ReflectionUtil; import java.security.AccessController; import java.security.PrivilegedAction; import java.util.ArrayList; +import java.util.HashSet; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; @@ -150,6 +151,8 @@ public abstract class GLDrawableFactory { eglFactory = tmp; } + private AbstractGraphicsDevice defaultSharedDevice = null; + protected GLDrawableFactory() { synchronized(glDrawableFactories) { glDrawableFactories.add(this); @@ -168,6 +171,55 @@ public abstract class GLDrawableFactory { protected abstract void shutdownInstance(); + /** + * Retrieve the default <code>device</code> {@link AbstractGraphicsDevice#getConnection()}. for this factory<br> + * The implementation must return a non <code>null</code> default device, which must not be opened, ie. it's native handle may be <code>null</code>. + * @return the default shared device for this factory, eg. :0.0 on X11 desktop. + */ + public abstract AbstractGraphicsDevice getDefaultDevice(); + + /** + * @return true if the device is compatible with this factory, ie. if it can be used for creation. Otherwise false. + */ + public abstract boolean getIsDeviceCompatible(AbstractGraphicsDevice device); + + /** + * Returns true if a shared context is already mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, + * or if a new shared context could be created and mapped. Otherwise return false.<br> + * Creation of the shared context is tried only once. + * + * @param device if <code>null</code>, the platform default device is being used + */ + public final boolean getIsSharedContextAvailable(AbstractGraphicsDevice device) { + return null != getOrCreateSharedContext(device); + } + + /** + * Returns the shared context mapped to the <code>device</code> {@link AbstractGraphicsDevice#getConnection()}, + * either a preexisting or newly created, or <code>null</code> if creation failed or not supported.<br> + * Creation of the shared context is tried only once. + * + * @param device if <code>null</code>, the platform default device is being used + */ + protected final GLContext getOrCreateSharedContext(AbstractGraphicsDevice device) { + if(null==device) { + device = getDefaultDevice(); + if(null==device) { + throw new InternalError("no default device"); + } + if (GLProfile.DEBUG) { + System.err.println("Info: GLDrawableFactory.getOrCreateSharedContext: using default device : "+device); + } + } else if( !getIsDeviceCompatible(device) ) { + if (GLProfile.DEBUG) { + System.err.println("Info: GLDrawableFactory.getOrCreateSharedContext: device not compatible : "+device); + } + return null; + } + return getOrCreateSharedContextImpl(device); + } + protected abstract GLContext getOrCreateSharedContextImpl(AbstractGraphicsDevice device); + /** * Returns the sole GLDrawableFactory instance. * diff --git a/src/jogl/classes/javax/media/opengl/GLProfile.java b/src/jogl/classes/javax/media/opengl/GLProfile.java index c5f5a8511..4111eb5a2 100644 --- a/src/jogl/classes/javax/media/opengl/GLProfile.java +++ b/src/jogl/classes/javax/media/opengl/GLProfile.java @@ -40,7 +40,6 @@ package javax.media.opengl; import com.jogamp.common.GlueGenVersion; import com.jogamp.common.jvm.JVMUtil; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.common.util.VersionUtil; import com.jogamp.nativewindow.NativeWindowVersion; import com.jogamp.opengl.impl.Debug; import com.jogamp.opengl.impl.GLDrawableFactoryImpl; @@ -50,6 +49,7 @@ import com.jogamp.opengl.JoglVersion; import java.util.HashMap; import java.util.Iterator; import java.security.*; +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.fixedfunc.GLPointerFunc; import javax.media.nativewindow.NativeWindowFactory; @@ -104,18 +104,22 @@ public class GLProfile { AccessController.doPrivileged(new PrivilegedAction() { public Object run() { registerFactoryShutdownHook(); - initProfiles(firstUIActionOnProcess); + initProfilesForDefaultDevices(firstUIActionOnProcess); return null; } }); - - if(null==defaultGLProfile) { - throw new GLException("No profile available: "+array2String(GL_PROFILE_LIST_ALL)+", "+glAvailabilityToString()); - } } } /** + * Trigger eager initialization of GLProfiles for the given device, + * in case it isn't done yet. + */ + public static void initProfiles(AbstractGraphicsDevice device) { + getProfileMap(device); + } + + /** * Manual shutdown method, may be called after your last JOGL use * within the running JVM.<br> * This method is called via the JVM shutdown hook.<br> @@ -132,87 +136,169 @@ public class 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); } - - public static final String glAvailabilityToString() { + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL4bc); + } + + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL4); + } + + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL3bc); + } + + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL3); + } + + public static boolean isGL2Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL2); + } + + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GLES2); + } + + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GLES1); + } + + public static boolean isGL2ES1Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL2ES1); + } + + public static boolean isGL2ES2Available(AbstractGraphicsDevice device) { + return null != getProfileMap(device).get(GL2ES2); + } + + /** Uses the default device */ + public static boolean isGL4bcAvailable() { + return isGL4bcAvailable(null); + } + + /** Uses the default device */ + public static boolean isGL4Available() { + return isGL4Available(null); + } + + /** Uses the default device */ + public static boolean isGL3bcAvailable() { + return isGL3bcAvailable(null); + } + + /** Uses the default device */ + public static boolean isGL3Available() { + return isGL3Available(null); + } + + /** Uses the default device */ + public static boolean isGL2Available() { + return isGL2Available(null); + } + + /** Uses the default device */ + public static boolean isGLES2Available() { + return isGLES2Available(null); + } + + /** Uses the default device */ + public static boolean isGLES1Available() { + return isGLES1Available(null); + } + + /** Uses the default device */ + public static boolean isGL2ES1Available() { + return isGL2ES1Available(null); + } + + /** Uses the default device */ + public static boolean isGL2ES2Available() { + return isGL2ES2Available(null); + } + + public static String glAvailabilityToString(AbstractGraphicsDevice device) { boolean avail; StringBuffer sb = new StringBuffer(); + validateInitialization(); + + if(null==device) { + device = defaultDevice; + } + sb.append("GLAvailability[Native[GL4bc "); - avail=isGL4bcAvailable(); + avail=isGL4bcAvailable(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 4, GLContext.CTX_PROFILE_COMPAT); + glAvailabilityToString(device, sb, 4, GLContext.CTX_PROFILE_COMPAT); } sb.append(", GL4 "); - avail=isGL4Available(); + avail=isGL4Available(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 4, GLContext.CTX_PROFILE_CORE); + glAvailabilityToString(device, sb, 4, GLContext.CTX_PROFILE_CORE); } sb.append(", GL3bc "); - avail=isGL3bcAvailable(); + avail=isGL3bcAvailable(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 3, GLContext.CTX_PROFILE_COMPAT); + glAvailabilityToString(device, sb, 3, GLContext.CTX_PROFILE_COMPAT); } sb.append(", GL3 "); - avail=isGL3Available(); + avail=isGL3Available(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 3, GLContext.CTX_PROFILE_CORE); + glAvailabilityToString(device, sb, 3, GLContext.CTX_PROFILE_CORE); } sb.append(", GL2 "); - avail=isGL2Available(); + avail=isGL2Available(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 2, GLContext.CTX_PROFILE_COMPAT); + glAvailabilityToString(device, sb, 2, GLContext.CTX_PROFILE_COMPAT); } sb.append(", GL2ES1 "); - sb.append(isGL2ES1Available()); + sb.append(isGL2ES1Available(device)); sb.append(", GLES1 "); - avail=isGLES1Available(); + avail=isGLES1Available(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 1, GLContext.CTX_PROFILE_ES); + glAvailabilityToString(device, sb, 1, GLContext.CTX_PROFILE_ES); } sb.append(", GL2ES2 "); - sb.append(isGL2ES2Available()); + sb.append(isGL2ES2Available(device)); sb.append(", GLES2 "); - avail=isGLES2Available(); + avail=isGLES2Available(device); sb.append(avail); if(avail) { - glAvailabilityToString(sb, 2, GLContext.CTX_PROFILE_ES); + glAvailabilityToString(device, sb, 2, GLContext.CTX_PROFILE_ES); } sb.append("], Profiles["); - for(Iterator i=mappedProfiles.values().iterator(); i.hasNext(); ) { + for(Iterator i=getProfileMap(device).values().iterator(); i.hasNext(); ) { sb.append(((GLProfile)i.next()).toString()); sb.append(", "); } sb.append(", default "); - sb.append(defaultGLProfile); + sb.append(getDefault(device)); sb.append("]]"); return sb.toString(); } + /** Uses the default device */ + public static String glAvailabilityToString() { + return glAvailabilityToString(null); + } + // // Public (user-visible) profiles // @@ -249,6 +335,9 @@ public class GLProfile { /** 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. @@ -337,12 +426,14 @@ public class GLProfile { * It selects the first of the set {@link GLProfile#GL_PROFILE_LIST_ALL} * @see #GL_PROFILE_LIST_ALL */ - public static final GLProfile getDefault() { - validateInitialization(); - if(null==defaultGLProfile) { - throw new GLException("No default profile available"); // should never be reached - } - return defaultGLProfile; + public static GLProfile getDefault(AbstractGraphicsDevice device) { + GLProfile glp = get(device, GL_DEFAULT); + return glp; + } + + /** Uses the default device */ + public static GLProfile getDefault() { + return getDefault(defaultDevice); } /** @@ -352,7 +443,14 @@ public class GLProfile { * @throws GLException if no implementation for the given profile is found. * @see #GL_PROFILE_LIST_MAX_FIXEDFUNC */ - public static final GLProfile getMaxFixedFunc() + public static GLProfile getMaxFixedFunc(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_MAX_FIXEDFUNC); + } + + /** Uses the default device */ + public static GLProfile getMaxFixedFunc() throws GLException { return get(GL_PROFILE_LIST_MAX_FIXEDFUNC); @@ -365,7 +463,14 @@ public class GLProfile { * @throws GLException if no implementation for the given profile is found. * @see #GL_PROFILE_LIST_MAX_PROGSHADER */ - public static final GLProfile getMaxProgrammable() + public static GLProfile getMaxProgrammable(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_MAX_PROGSHADER); + } + + /** Uses the default device */ + public static GLProfile getMaxProgrammable() throws GLException { return get(GL_PROFILE_LIST_MAX_PROGSHADER); @@ -378,7 +483,14 @@ public class GLProfile { * @throws GLException if no implementation for the given profile is found. * @see #GL_PROFILE_LIST_GL2ES1 */ - public static final GLProfile getGL2ES1() + public static GLProfile getGL2ES1(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_GL2ES1); + } + + /** Uses the default device */ + public static GLProfile getGL2ES1() throws GLException { return get(GL_PROFILE_LIST_GL2ES1); @@ -391,29 +503,40 @@ public class GLProfile { * @throws GLException if no implementation for the given profile is found. * @see #GL_PROFILE_LIST_GL2ES2 */ - public static final GLProfile getGL2ES2() + public static GLProfile getGL2ES2(AbstractGraphicsDevice device) + throws GLException + { + return get(device, GL_PROFILE_LIST_GL2ES2); + } + + /** Uses the default device */ + public static GLProfile getGL2ES2() throws GLException { return get(GL_PROFILE_LIST_GL2ES2); } /** Returns a GLProfile object. - * Verfifies the given profile and chooses an apropriate implementation. + * verifies the given profile and chooses an appropriate implementation. * A generic value of <code>null</code> or <code>GL</code> will result in * the default profile. * * @throws GLException if no implementation for the given profile is found. */ - public static final GLProfile get(String profile) + public static GLProfile get(AbstractGraphicsDevice device, String profile) throws GLException { - validateInitialization(); - 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"); + if(null==profile || profile.equals("GL")) { + profile = GL_DEFAULT; } - return glProfile; + return (GLProfile) getProfileMap(device).get(profile); + } + + /** Uses the default device */ + public static GLProfile get(String profile) + throws GLException + { + return get(defaultDevice, profile); } /** @@ -422,36 +545,43 @@ public class GLProfile { * * @throws GLException if no implementation for the given profile is found. */ - public static final GLProfile get(String[] profiles) + public static GLProfile get(AbstractGraphicsDevice device, String[] profiles) throws GLException { - validateInitialization(); + HashMap map = getProfileMap(device); for(int i=0; i<profiles.length; i++) { String profile = profiles[i]; - GLProfile glProfile = (GLProfile) mappedProfiles.get(profile); + GLProfile glProfile = (GLProfile) map.get(profile); if(null!=glProfile) { return glProfile; } } - throw new GLException("Profiles "+array2String(profiles)+" not available"); + throw new GLException("Profiles "+array2String(profiles)+" not available on device "+device); + } + + /** Uses the default device */ + public static GLProfile get(String[] profiles) + throws GLException + { + return get(defaultDevice, profiles); } /** Indicates whether the native OpenGL ES1 profile is in use. * This requires an EGL interface. */ - public static final boolean usesNativeGLES1(String profileImpl) { + public static boolean usesNativeGLES1(String profileImpl) { return GLES1.equals(profileImpl); } /** Indicates whether the native OpenGL ES2 profile is in use. - * This requires an EGL interface. + * This requires an EGL or ES2 compatible interface. */ - public static final boolean usesNativeGLES2(String profileImpl) { + public static boolean usesNativeGLES2(String profileImpl) { return GLES2.equals(profileImpl); } /** Indicates whether either of the native OpenGL ES profiles are in use. */ - public static final boolean usesNativeGLES(String profileImpl) { + public static boolean usesNativeGLES(String profileImpl) { return usesNativeGLES2(profileImpl) || usesNativeGLES1(profileImpl); } @@ -922,20 +1052,16 @@ public class GLProfile { private static /*final*/ boolean isAWTAvailable; + private static /*final*/ boolean hasDesktopGL; private static /*final*/ boolean hasGL234Impl; - private static /*final*/ boolean hasGL4bcImpl; - private static /*final*/ boolean hasGL4Impl; - private static /*final*/ boolean hasGL3bcImpl; - private static /*final*/ boolean hasGL3Impl; - private static /*final*/ boolean hasGL2Impl; private static /*final*/ boolean hasGLES2Impl; private static /*final*/ boolean hasGLES1Impl; - /** The JVM/process wide default GL profile **/ - private static /*final*/ GLProfile defaultGLProfile; - - /** All GLProfiles */ - private static /*final*/ HashMap/*<String, GLProfile>*/ mappedProfiles; + private static /*final*/ GLDrawableFactoryImpl eglFactory; + private static /*final*/ GLDrawableFactoryImpl desktopFactory; + private static /*final*/ AbstractGraphicsDevice defaultDevice; + private static /*final*/ AbstractGraphicsDevice defaultDesktopDevice; + private static /*final*/ AbstractGraphicsDevice defaultEGLDevice; static boolean initialized = false; @@ -947,7 +1073,11 @@ public class GLProfile { * Tries the profiles implementation and native libraries. * Throws an GLException if no profile could be found at all. */ - private static void initProfiles(boolean firstUIActionOnProcess) { + private static void initProfilesForDefaultDevices(boolean firstUIActionOnProcess) { + + if(DEBUG) { + System.err.println("GLProfile.init firstUIActionOnProcess "+firstUIActionOnProcess); + } NativeWindowFactory.initSingleton(firstUIActionOnProcess); @@ -957,17 +1087,7 @@ public class GLProfile { ReflectionUtil.isClassAvailable("javax.media.opengl.awt.GLCanvas", classloader) ; // JOGL hasGL234Impl = ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.gl4.GL4bcImpl", classloader); - hasGL4bcImpl = hasGL234Impl; - hasGL4Impl = hasGL234Impl; - hasGL3bcImpl = hasGL234Impl; - hasGL3Impl = hasGL234Impl; - hasGL2Impl = hasGL234Impl; - mappedProfiles = computeProfileMap(); - - boolean hasDesktopGL = false; - boolean hasNativeOSFactory = false; - Throwable t; - + // // Iteration of desktop GL availability detection // utilizing the detected GL version in the shared context. @@ -975,14 +1095,12 @@ public class GLProfile { // - Instantiate GLDrawableFactory incl its shared dummy drawable/context, // which will register at GLContext .. // - - t=null; + Throwable t=null; // if successfull it has a shared dummy drawable and context created try { - GLDrawableFactoryImpl factory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2); - hasNativeOSFactory = null != factory; - if(hasNativeOSFactory) { - DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) factory.getGLDynamicLookupHelper(0); + desktopFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GL2); + if(null != desktopFactory) { + DesktopGLDynamicLookupHelper glLookupHelper = (DesktopGLDynamicLookupHelper) desktopFactory.getGLDynamicLookupHelper(0); if(null!=glLookupHelper) { hasDesktopGL = glLookupHelper.hasGLBinding(); } @@ -998,43 +1116,29 @@ public class GLProfile { if(null!=t) { t.printStackTrace(); } - if(!hasNativeOSFactory) { - System.err.println("Info: GLProfile.init - Native platform GLDrawable factory not available"); + if(null == desktopFactory) { + System.err.println("Info: GLProfile.init - Desktop GLDrawable factory not available"); } } - if(hasDesktopGL && !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) { + if(null == desktopFactory) { hasDesktopGL = false; hasGL234Impl = false; - hasGL4bcImpl = false; - hasGL4Impl = false; - hasGL3bcImpl = false; - hasGL3Impl = false; - hasGL2Impl = false; } else { - hasGL4bcImpl = hasGL4bcImpl && GLContext.isGL4bcAvailable(); - hasGL4Impl = hasGL4Impl && GLContext.isGL4Available(); - hasGL3bcImpl = hasGL3bcImpl && GLContext.isGL3bcAvailable(); - hasGL3Impl = hasGL3Impl && GLContext.isGL3Available(); - hasGL2Impl = hasGL2Impl && GLContext.isGL2Available(); + defaultDesktopDevice = desktopFactory.getDefaultDevice(); + defaultDevice = defaultDesktopDevice; } if ( ReflectionUtil.isClassAvailable("com.jogamp.opengl.impl.egl.EGLDrawableFactory", classloader) ) { t=null; try { - GLDrawableFactoryImpl factory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); - if(null != factory) { - GLDynamicLookupHelper eglLookupHelper = factory.getGLDynamicLookupHelper(2); + eglFactory = (GLDrawableFactoryImpl) GLDrawableFactory.getFactoryImpl(GLES2); + if(null != eglFactory) { + GLDynamicLookupHelper eglLookupHelper = eglFactory.getGLDynamicLookupHelper(2); if(null!=eglLookupHelper) { hasGLES2Impl = eglLookupHelper.isLibComplete(); } - eglLookupHelper = factory.getGLDynamicLookupHelper(1); + eglLookupHelper = eglFactory.getGLDynamicLookupHelper(1); if(null!=eglLookupHelper) { hasGLES1Impl = eglLookupHelper.isLibComplete(); } @@ -1048,30 +1152,151 @@ public class GLProfile { } catch (RuntimeException re) { t=re; } - if(DEBUG && null!=t) { - t.printStackTrace(); + if(DEBUG) { + if(null!=t) { + t.printStackTrace(); + } + if(null == eglFactory) { + System.err.println("Info: GLProfile.init - EGL GLDrawable factory not available"); + } } } - if(hasGLES2Impl) { - GLContext.mapVersionAvailable(2, GLContext.CTX_PROFILE_ES, 2, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY); + + if(null == eglFactory) { + hasGLES2Impl = false; + hasGLES1Impl = false; + } else { + defaultEGLDevice = eglFactory.getDefaultDevice(); + if (null==defaultDevice) { + defaultDevice = defaultEGLDevice; + } + } + + boolean addedAnyProfile = initProfilesForDevice(defaultDesktopDevice); + addedAnyProfile = addedAnyProfile || initProfilesForDevice(defaultEGLDevice); + + if(DEBUG) { + System.err.println(GlueGenVersion.getInstance()); + System.err.println(NativeWindowVersion.getInstance()); + System.err.print(JoglVersion.getInstance()); + + System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable); + System.err.println("GLProfile.init has desktopFactory "+(null!=desktopFactory)); + System.err.println("GLProfile.init hasDesktopGL "+hasDesktopGL); + System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl); + System.err.println("GLProfile.init has eglFactory "+(null!=eglFactory)); + System.err.println("GLProfile.init hasGLES1Impl "+hasGLES1Impl); + System.err.println("GLProfile.init hasGLES2Impl "+hasGLES2Impl); + System.err.println("GLProfile.init defaultDesktopDevice "+defaultDevice); + System.err.println("GLProfile.init defaultEGLDevice "+defaultDevice); + System.err.println("GLProfile.init defaultDevice "+defaultDevice); + } + + if(!addedAnyProfile) { + throw new GLException("No profile available: "+array2String(GL_PROFILE_LIST_ALL)+", "+ glAvailabilityToString()); } - if(hasGLES1Impl) { - GLContext.mapVersionAvailable(1, GLContext.CTX_PROFILE_ES, 1, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY); + } + + /** + * @param device the device for which profiles shall be initialized + * @return true if any profile for the device exists, otherwise false + */ + private static synchronized boolean initProfilesForDevice(AbstractGraphicsDevice device) { + boolean isSet = GLContext.getAvailableGLVersionsSet(device); + + if(DEBUG) { + String msg = "Info: GLProfile.initProfilesForDevice: "+device.getConnection()+", isSet "+isSet; + Throwable t = new Throwable(msg); + t.printStackTrace(); + // System.err.println(msg); + } + if(isSet) { + return null != GLProfile.getDefault(device); + } + + boolean addedAnyProfile = false; + + if( hasDesktopGL && desktopFactory.getIsDeviceCompatible(device)) { + // 1st pretend we have all Desktop and EGL profiles .. + computeProfileMap(device, true /* desktopCtxUndef*/, true /* eglCtxUndef */); + + // Triggers eager initialization of share context in GLDrawableFactory for the device, + // hence querying all available GLProfiles + boolean desktopSharedCtxAvail = desktopFactory.getIsSharedContextAvailable(device); + if (DEBUG) { + System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": desktop Shared Ctx "+desktopSharedCtxAvail); + } + if( null == GLContext.getAvailableGLVersion(device, 2, GLContext.CTX_PROFILE_COMPAT) ) { + // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, + // so we have to add the usual suspect + GLContext.mapAvailableGLVersion(device, + 2, GLContext.CTX_PROFILE_COMPAT, + 1, 5, GLContext.CTX_PROFILE_COMPAT|GLContext.CTX_OPTION_ANY); + } + computeProfileMap(device, false /* desktopCtxUndef*/, false /* eglCtxUndef */); + addedAnyProfile = null != GLProfile.getDefault(device); + } else { + if(DEBUG) { + System.err.println("GLProfile: DesktopFactory - Device is not available: "+device.getConnection()); + } } - mappedProfiles = computeProfileMap(); + if( null!=eglFactory && ( hasGLES2Impl || hasGLES1Impl ) && eglFactory.getIsDeviceCompatible(device)) { + // 1st pretend we have all EGL profiles .. + computeProfileMap(device, false /* desktopCtxUndef*/, true /* eglCtxUndef */); + + // Triggers eager initialization of share context in GLDrawableFactory for the device, + // hence querying all available GLProfiles + boolean eglSharedCtxAvail = eglFactory.getIsSharedContextAvailable(device); + if (DEBUG) { + System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": egl Shared Ctx "+eglSharedCtxAvail); + } + if(hasGLES2Impl && null == GLContext.getAvailableGLVersion(device, 2, GLContext.CTX_PROFILE_ES) ) { + // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, + // so we have to add the usual suspect + GLContext.mapAvailableGLVersion(device, + 2, GLContext.CTX_PROFILE_ES, + 2, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY); + } + if(hasGLES1Impl && null == GLContext.getAvailableGLVersion(device, 1, GLContext.CTX_PROFILE_ES)) { + // nobody yet set the available desktop versions, see {@link GLContextImpl#makeCurrent}, + // so we have to add the usual suspect + GLContext.mapAvailableGLVersion(device, + 1, GLContext.CTX_PROFILE_ES, + 1, 0, GLContext.CTX_PROFILE_ES|GLContext.CTX_OPTION_ANY); + } + computeProfileMap(device, false /* desktopCtxUndef*/, false /* eglCtxUndef */); + addedAnyProfile = addedAnyProfile || null != GLProfile.getDefault(device); + } else { + if(DEBUG) { + System.err.println("GLProfile: EGLFactory - Device is not available: "+device.getConnection()); + } + } + if(!GLContext.getAvailableGLVersionsSet(device)) { + GLContext.setAvailableGLVersionsSet(device); + } if (DEBUG) { - System.err.println(GlueGenVersion.getInstance().getInfo(null)); - System.err.println(NativeWindowVersion.getInstance().getInfo(null)); - System.err.print(JoglVersion.getInstance().getInfo(null)); - System.err.println("GLProfile.init firstUIActionOnProcess "+firstUIActionOnProcess); - System.err.println("GLProfile.init isAWTAvailable "+isAWTAvailable); - System.err.println("GLProfile.init hasNativeOSFactory "+hasNativeOSFactory); - System.err.println("GLProfile.init hasDesktopGL "+hasDesktopGL); - System.err.println("GLProfile.init hasGL234Impl "+hasGL234Impl); - System.err.println("GLProfile.init "+glAvailabilityToString()); + System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": added profile(s): "+addedAnyProfile); + System.err.println("GLProfile.initProfilesForDevice: "+device.getConnection()+": "+glAvailabilityToString(device)); } + + return addedAnyProfile; + } + + public static AbstractGraphicsDevice getDefaultDevice() { + validateInitialization(); + return defaultDevice; + } + + public static AbstractGraphicsDevice getDefaultDesktopDevice() { + validateInitialization(); + return defaultDesktopDevice; + } + + public static AbstractGraphicsDevice getDefaultEGLDevice() { + validateInitialization(); + return defaultEGLDevice; } private static synchronized void registerFactoryShutdownHook() { @@ -1102,7 +1327,7 @@ public class GLProfile { } } - private static final String array2String(String[] list) { + private static String array2String(String[] list) { StringBuffer msg = new StringBuffer(); msg.append("["); for (int i = 0; i < list.length; i++) { @@ -1114,8 +1339,8 @@ public class GLProfile { return msg.toString(); } - private static final void glAvailabilityToString(StringBuffer sb, int major, int profile) { - String str = GLContext.getGLVersionAvailable(major, profile); + private static void glAvailabilityToString(AbstractGraphicsDevice device, StringBuffer sb, int major, int profile) { + String str = GLContext.getAvailableGLVersionAsString(device, major, profile); if(null==str) { throw new GLException("Internal Error"); } @@ -1124,103 +1349,152 @@ public class GLProfile { sb.append("]"); } - private static HashMap computeProfileMap() { - defaultGLProfile=null; - HashMap/*<String, GLProfile>*/ _mappedProfiles = new HashMap(GL_PROFILE_LIST_ALL.length); + private static void computeProfileMap(AbstractGraphicsDevice device, boolean desktopCtxUndef, boolean eglCtxUndef) { + if (DEBUG) { + System.err.println("GLProfile.init map "+device.getConnection()+", desktopCtxUndef "+desktopCtxUndef+", eglCtxUndef "+eglCtxUndef); + } + GLProfile defaultGLProfile = null; + HashMap/*<String, GLProfile>*/ _mappedProfiles = new HashMap(GL_PROFILE_LIST_ALL.length + 1 /* default */); for(int i=0; i<GL_PROFILE_LIST_ALL.length; i++) { String profile = GL_PROFILE_LIST_ALL[i]; - String profileImpl = computeProfileImpl(profile); + String profileImpl = computeProfileImpl(device, profile, desktopCtxUndef, eglCtxUndef); if(null!=profileImpl) { GLProfile glProfile = new GLProfile(profile, profileImpl); _mappedProfiles.put(profile, glProfile); if (DEBUG) { - System.err.println("GLProfile.init map "+glProfile); + System.err.println("GLProfile.init map "+glProfile+" on devide "+device.getConnection()); } if(null==defaultGLProfile) { defaultGLProfile=glProfile; if (DEBUG) { - System.err.println("GLProfile.init default "+glProfile); + System.err.println("GLProfile.init map default "+glProfile+" on device "+device.getConnection()); } } } else { if (DEBUG) { - System.err.println("GLProfile.init map *** no mapping for "+profile); + System.err.println("GLProfile.init map *** no mapping for "+profile+" on device "+device.getConnection()); } } } - return _mappedProfiles; - } - - private static final String getGLImplBaseClassName(String profileImpl) { - if ( GL4bc.equals(profileImpl) || - GL4.equals(profileImpl) || - GL3bc.equals(profileImpl) || - GL3.equals(profileImpl) || - GL2.equals(profileImpl) ) { - return "com.jogamp.opengl.impl.gl4.GL4bc"; - } else if(GLES1.equals(profileImpl) || GL2ES1.equals(profileImpl)) { - return "com.jogamp.opengl.impl.es1.GLES1"; - } else if(GLES2.equals(profileImpl) || GL2ES2.equals(profileImpl)) { - return "com.jogamp.opengl.impl.es2.GLES2"; - } else { - throw new GLException("unsupported profile \"" + profileImpl + "\""); + if(null!=defaultGLProfile) { + _mappedProfiles.put(GL_DEFAULT, defaultGLProfile); } + setProfileMap(device, _mappedProfiles); } /** * Returns the profile implementation */ - private static String computeProfileImpl(String profile) { + private static String computeProfileImpl(AbstractGraphicsDevice device, String profile, boolean desktopCtxUndef, boolean eglCtxUndef) { if (GL2ES1.equals(profile)) { - if(hasGL2Impl) { - return GL2; - } else if(hasGL3bcImpl) { - return GL3bc; - } else if(hasGL4bcImpl) { - return GL4bc; - } else if(hasGLES1Impl) { + if(hasGL234Impl) { + if(desktopCtxUndef || GLContext.isGL2Available(device)) { + return GL2; + } else if(GLContext.isGL3bcAvailable(device)) { + return GL3bc; + } else if(GLContext.isGL4bcAvailable(device)) { + return GL4bc; + } + } + if(hasGLES1Impl && ( eglCtxUndef || GLContext.isGLES1Available(device))) { return GLES1; } } else if (GL2ES2.equals(profile)) { - if(hasGL2Impl) { - return GL2; - } else if(hasGL3Impl) { - return GL3; - } else if(hasGL4Impl) { - return GL4; - } else if(hasGLES2Impl) { + if(hasGL234Impl) { + if(desktopCtxUndef || GLContext.isGL2Available(device)) { + return GL2; + } else if(GLContext.isGL3Available(device)) { + return GL3; + } else if(GLContext.isGL4Available(device)) { + return GL4; + } + } + if(hasGLES2Impl && ( eglCtxUndef || GLContext.isGLES2Available(device))) { return GLES2; } } else if(GL2GL3.equals(profile)) { - if(hasGL2Impl) { - return GL2; - } else if(hasGL3bcImpl) { - return GL3bc; - } else if(hasGL4bcImpl) { - return GL4bc; - } else if(hasGL3Impl) { - return GL3; - } else if(hasGL4Impl) { - return GL4; + if(hasGL234Impl) { + if(desktopCtxUndef || GLContext.isGL2Available(device)) { + return GL2; + } else if(GLContext.isGL3bcAvailable(device)) { + return GL3bc; + } else if(GLContext.isGL4bcAvailable(device)) { + return GL4bc; + } else if(GLContext.isGL3Available(device)) { + return GL3; + } else if(GLContext.isGL4Available(device)) { + return GL4; + } } - } else if(GL4bc.equals(profile) && hasGL4bcImpl) { + } else if(GL4bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4bcAvailable(device))) { return GL4bc; - } else if(GL4.equals(profile) && hasGL4Impl) { + } else if(GL4.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL4Available(device))) { return GL4; - } else if(GL3bc.equals(profile) && hasGL3bcImpl) { + } else if(GL3bc.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3bcAvailable(device))) { return GL3bc; - } else if(GL3.equals(profile) && hasGL3Impl) { + } else if(GL3.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL3Available(device))) { return GL3; - } else if(GL2.equals(profile) && hasGL2Impl) { + } else if(GL2.equals(profile) && hasGL234Impl && ( desktopCtxUndef || GLContext.isGL2Available(device))) { return GL2; - } else if(GLES2.equals(profile) && hasGLES2Impl) { + } else if(GLES2.equals(profile) && hasGLES2Impl && ( eglCtxUndef || GLContext.isGLES2Available(device))) { return GLES2; - } else if(GLES1.equals(profile) && hasGLES1Impl) { + } else if(GLES1.equals(profile) && hasGLES1Impl && ( eglCtxUndef || GLContext.isGLES1Available(device))) { return GLES1; } return null; } + private static String getGLImplBaseClassName(String profileImpl) { + if ( GL4bc.equals(profileImpl) || + GL4.equals(profileImpl) || + GL3bc.equals(profileImpl) || + GL3.equals(profileImpl) || + GL2.equals(profileImpl) ) { + return "com.jogamp.opengl.impl.gl4.GL4bc"; + } else if(GLES1.equals(profileImpl) || GL2ES1.equals(profileImpl)) { + return "com.jogamp.opengl.impl.es1.GLES1"; + } else if(GLES2.equals(profileImpl) || GL2ES2.equals(profileImpl)) { + return "com.jogamp.opengl.impl.es2.GLES2"; + } else { + throw new GLException("unsupported profile \"" + profileImpl + "\""); + } + } + + private static /*final*/ HashMap/*<device_connection, HashMap<GL-String, GLProfile>*/ deviceConn2ProfileMap = new HashMap(); + + /** + * This implementation support lazy initialization, while avoiding recursion/deadlocks.<br> + * If no mapping 'device -> GLProfiles-Map' exists yet, it triggers<br> + * - create empty mapping device -> GLProfiles-Map <br> + * - initialization<br< + * + * @param device the key 'device -> GLProfiles-Map' + * @return the GLProfile HashMap + */ + private static HashMap getProfileMap(AbstractGraphicsDevice device) { + validateInitialization(); + if(null==device) { + device = defaultDevice; + } + String deviceKey = GLContext.getUniqueDeviceString(device); + HashMap map = (HashMap) deviceConn2ProfileMap.get(deviceKey); + if(null==map) { + map = new HashMap(); + synchronized ( deviceConn2ProfileMap ) { + deviceConn2ProfileMap.put(deviceKey, map); + } + initProfilesForDevice(device); + } + return map; + } + + private static void setProfileMap(AbstractGraphicsDevice device, HashMap/*<GL-String, GLProfile>*/mappedProfiles) { + validateInitialization(); + synchronized ( deviceConn2ProfileMap ) { + deviceConn2ProfileMap.put(GLContext.getUniqueDeviceString(device), mappedProfiles); + } + } + private GLProfile(String profile, String profileImpl) { this.profile = profile; this.profileImpl = profileImpl; diff --git a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java index 9db718bfb..c0f2736fb 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLCanvas.java @@ -83,7 +83,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { static { DEBUG = Debug.debug("GLCanvas"); - defaultGLProfile = GLProfile.getDefault(); + defaultGLProfile = GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()); } private GLProfile glProfile; @@ -795,11 +795,11 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { * A most simple JOGL AWT test entry */ public static void main(String args[]) { - System.err.println(GlueGenVersion.getInstance().getInfo(null)); - System.err.println(NativeWindowVersion.getInstance().getInfo(null)); - System.err.print(JoglVersion.getInstance().getInfo(null)); + System.err.println(GlueGenVersion.getInstance()); + System.err.println(NativeWindowVersion.getInstance()); + System.err.print(JoglVersion.getInstance()); - GLCapabilities caps = new GLCapabilities( GLProfile.getDefault() ); + GLCapabilities caps = new GLCapabilities( GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()) ); Frame frame = new Frame("JOGL AWT Test"); GLCanvas glCanvas = new GLCanvas(caps); @@ -809,7 +809,7 @@ public class GLCanvas extends Canvas implements AWTGLAutoDrawable { glCanvas.addGLEventListener(new GLEventListener() { public void init(GLAutoDrawable drawable) { GL gl = drawable.getGL(); - System.err.println(JoglVersion.getInstance().getGLInfo(gl, null)); + System.err.println(JoglVersion.getInstance().toString(gl)); } public void reshape(GLAutoDrawable drawable, int x, int y, int width, int height) { diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index b9bbf71c2..955e51e69 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -1275,7 +1275,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable { public GLProfile getGLProfile() { // FIXME: should do better than this; is it possible to using only platform-independent code? - return GLProfile.getDefault(); + return GLProfile.getDefault(GLProfile.getDefaultDesktopDevice()); } public void handleReshape() { diff --git a/src/junit/com/jogamp/test/junit/newt/TestGLWindows00NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestGLWindows00NEWT.java new file mode 100644 index 000000000..5568f2e1a --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestGLWindows00NEWT.java @@ -0,0 +1,132 @@ +/** + * Copyright 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.test.junit.newt; + +import org.junit.Assert; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.media.opengl.*; + +import com.jogamp.newt.*; +import com.jogamp.newt.event.*; +import com.jogamp.newt.opengl.*; +import java.io.IOException; + +import com.jogamp.test.junit.util.UITestCase; +import com.jogamp.test.junit.util.MiscUtils; +import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; +import javax.media.nativewindow.AbstractGraphicsDevice; + +public class TestGLWindows00NEWT extends UITestCase { + static GLProfile glp; + static int width, height; + static long durationPerTest = 100; // ms + + @BeforeClass + public static void initClass() { + GLProfile.initSingleton(true); + // GLProfile.initSingleton(false); + width = 640; + height = 480; + glp = GLProfile.getDefault(); + } + + static GLWindow createWindow(Screen screen, GLCapabilities caps) + throws InterruptedException + { + Assert.assertNotNull(caps); + // + // Create native windowing resources .. X11/Win/OSX + // + GLWindow glWindow; + if(null!=screen) { + glWindow = GLWindow.create(screen, caps); + Assert.assertNotNull(glWindow); + } else { + glWindow = GLWindow.create(caps); + Assert.assertNotNull(glWindow); + } + + GLEventListener demo = new Gears(); + glWindow.addGLEventListener(demo); + + glWindow.setSize(512, 512); + glWindow.setVisible(true); + Assert.assertEquals(true,glWindow.isVisible()); + Assert.assertEquals(true,glWindow.isNativeValid()); + + return glWindow; + } + + static void destroyWindow(GLWindow glWindow) { + if(null!=glWindow) { + glWindow.destroy(true); + Assert.assertEquals(false,glWindow.isNativeValid()); + } + } + + @Test + public void testWindow00() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + GLWindow window1 = createWindow(null, caps); // local + Assert.assertEquals(true,window1.isNativeValid()); + Assert.assertEquals(true,window1.isVisible()); + AbstractGraphicsDevice device1 = window1.getScreen().getDisplay().getGraphicsDevice(); + + System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1)); + + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + destroyWindow(window1); + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } + } + System.out.println("durationPerTest: "+durationPerTest); + String tstname = TestGLWindows00NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/junit/com/jogamp/test/junit/newt/TestRemoteGLWindows01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestRemoteGLWindows01NEWT.java new file mode 100644 index 000000000..623651f2d --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestRemoteGLWindows01NEWT.java @@ -0,0 +1,161 @@ +/** + * Copyright 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.test.junit.newt; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.BeforeClass; +import org.junit.Test; + +import javax.media.opengl.*; +import com.jogamp.opengl.util.Animator; + +import com.jogamp.newt.*; +import com.jogamp.newt.opengl.*; +import java.io.IOException; + +import com.jogamp.test.junit.util.UITestCase; +import com.jogamp.test.junit.jogl.demos.gl2.gears.Gears; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeWindowException; + +public class TestRemoteGLWindows01NEWT extends UITestCase { + static GLProfile glp; + static int width, height; + static long durationPerTest = 100; // ms + + @BeforeClass + public static void initClass() { + GLProfile.initSingleton(true); + // GLProfile.initSingleton(false); + width = 640; + height = 480; + glp = GLProfile.getDefault(); + } + + static GLWindow createWindow(Screen screen, GLCapabilities caps) + throws InterruptedException + { + Assert.assertNotNull(caps); + // + // Create native windowing resources .. X11/Win/OSX + // + GLWindow glWindow; + if(null!=screen) { + glWindow = GLWindow.create(screen, caps); + Assert.assertNotNull(glWindow); + } else { + glWindow = GLWindow.create(caps); + Assert.assertNotNull(glWindow); + } + + GLEventListener demo = new Gears(); + glWindow.addGLEventListener(demo); + + glWindow.setSize(512, 512); + glWindow.setVisible(true); + Assert.assertEquals(true,glWindow.isVisible()); + Assert.assertEquals(true,glWindow.isNativeValid()); + + return glWindow; + } + + static void destroyWindow(GLWindow glWindow) { + if(null!=glWindow) { + glWindow.destroy(true); + Assert.assertEquals(false,glWindow.isNativeValid()); + } + } + + @Test + public void testRemoteWindow01() throws InterruptedException { + GLCapabilities caps = new GLCapabilities(glp); + Assert.assertNotNull(caps); + GLWindow window1 = createWindow(null, caps); // local + Assert.assertEquals(true,window1.isNativeValid()); + Assert.assertEquals(true,window1.isVisible()); + AbstractGraphicsDevice device1 = window1.getScreen().getDisplay().getGraphicsDevice(); + + System.err.println("GLProfiles window1: "+device1.getConnection()+": "+GLProfile.glAvailabilityToString(device1)); + + Animator animator1 = new Animator(window1); + animator1.start(); + + // Eager initialization of NEWT Display -> AbstractGraphicsDevice -> GLProfile (device) + Display display2 = NewtFactory.createDisplay("charelle:0.0"); // remote display + display2.setDestroyWhenUnused(true); + try { + display2.createNative(); + } catch (NativeWindowException nwe) { + System.err.println(nwe); + Assume.assumeNoException(nwe); + destroyWindow(window1); + return; + } + AbstractGraphicsDevice device2 = display2.getGraphicsDevice(); + GLProfile.initProfiles(device2); // just to make sure + System.err.println(""); + System.err.println("GLProfiles window2: "+device2.getConnection()+": "+GLProfile.glAvailabilityToString(device2)); + + Screen screen2 = NewtFactory.createScreen(display2, 0); // screen 0 + GLWindow window2 = createWindow(screen2, caps); // remote + Assert.assertEquals(true,window2.isNativeValid()); + Assert.assertEquals(true,window2.isVisible()); + + Animator animator2 = new Animator(window2); + animator2.start(); + + for(int state=0; state*100<durationPerTest; state++) { + Thread.sleep(100); + } + + destroyWindow(window1); + destroyWindow(window2); + } + + static int atoi(String a) { + int i=0; + try { + i = Integer.parseInt(a); + } catch (Exception ex) { ex.printStackTrace(); } + return i; + } + + public static void main(String args[]) throws IOException { + for(int i=0; i<args.length; i++) { + if(args[i].equals("-time")) { + durationPerTest = atoi(args[++i]); + } + } + System.out.println("durationPerTest: "+durationPerTest); + String tstname = TestRemoteGLWindows01NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} diff --git a/src/junit/com/jogamp/test/junit/newt/TestRemoteWindow01NEWT.java b/src/junit/com/jogamp/test/junit/newt/TestRemoteWindow01NEWT.java new file mode 100644 index 000000000..2a43c3ac5 --- /dev/null +++ b/src/junit/com/jogamp/test/junit/newt/TestRemoteWindow01NEWT.java @@ -0,0 +1,146 @@ +/** + * Copyright 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: + * + * 1. Redistributions of source code must retain the above copyright notice, this list of + * conditions and the following disclaimer. + * + * 2. Redistributions 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. + * + * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED + * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON + * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING + * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF + * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * The views and conclusions contained in the software and documentation are those of the + * authors and should not be interpreted as representing official policies, either expressed + * or implied, of JogAmp Community. + */ + +package com.jogamp.test.junit.newt; + +import java.lang.reflect.*; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.junit.Assert; +import org.junit.Assume; +import org.junit.Before; +import org.junit.BeforeClass; +import org.junit.After; +import org.junit.AfterClass; +import org.junit.Test; + +import javax.media.nativewindow.*; + +import com.jogamp.newt.*; +import java.io.IOException; + +import com.jogamp.test.junit.util.UITestCase; + +public class TestRemoteWindow01NEWT extends UITestCase { + static int width, height; + + @BeforeClass + public static void initClass() { + NativeWindowFactory.initSingleton(true); + width = 640; + height = 480; + } + + static Window createWindow(Screen screen, Capabilities caps, int width, int height, boolean onscreen, boolean undecorated) { + Assert.assertNotNull(caps); + caps.setOnscreen(onscreen); + // System.out.println("Requested: "+caps); + + // + // Create native windowing resources .. X11/Win/OSX + // + Window window = NewtFactory.createWindow(screen, caps); + Assert.assertNotNull(window); + window.setUndecorated(onscreen && undecorated); + window.setSize(width, height); + Assert.assertEquals(false,window.isNativeValid()); + Assert.assertEquals(false,window.isVisible()); + window.setVisible(true); + Assert.assertEquals(true,window.isVisible()); + Assert.assertEquals(true,window.isNativeValid()); + // Assert.assertEquals(width,window.getWidth()); + // Assert.assertEquals(height,window.getHeight()); + // System.out.println("Created: "+window); + + // + // Create native OpenGL resources .. XGL/WGL/CGL .. + // equivalent to GLAutoDrawable methods: setVisible(true) + // + caps = window.getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + Assert.assertNotNull(caps); + Assert.assertTrue(caps.getGreenBits()>5); + Assert.assertTrue(caps.getBlueBits()>5); + Assert.assertTrue(caps.getRedBits()>5); + Assert.assertEquals(caps.isOnscreen(),onscreen); + + return window; + } + + static void destroyWindow(Display display, Screen screen, Window window) { + if(null!=window) { + window.destroy(); + } + if(null!=screen) { + screen.destroy(); + } + if(null!=display) { + display.destroy(); + } + } + + @Test + public void testRemoteWindow01() throws InterruptedException { + Capabilities caps = new Capabilities(); + Display display1 = NewtFactory.createDisplay(null); // local display + Screen screen1 = NewtFactory.createScreen(display1, 0); // screen 0 + Window window1 = createWindow(screen1, caps, width, height, true /* onscreen */, false /* undecorated */); + window1.setVisible(true); + + Assert.assertEquals(true,window1.isNativeValid()); + Assert.assertEquals(true,window1.isVisible()); + + Display display2 = NewtFactory.createDisplay("charelle:0.0"); // remote display + try { + display2.createNative(); + } catch (NativeWindowException nwe) { + System.err.println(nwe); + Assume.assumeNoException(nwe); + destroyWindow(display1, screen1, window1); + return; + } + Screen screen2 = NewtFactory.createScreen(display2, 0); // screen 0 + Window window2 = createWindow(screen2, caps, width, height, true /* onscreen */, false /* undecorated */); + window2.setVisible(true); + + Assert.assertEquals(true,window2.isNativeValid()); + Assert.assertEquals(true,window2.isVisible()); + + Thread.sleep(500); // 500 ms + + destroyWindow(display1, screen1, window1); + destroyWindow(display2, screen2, window2); + } + + public static void main(String args[]) throws IOException { + String tstname = TestRemoteWindow01NEWT.class.getName(); + org.junit.runner.JUnitCore.main(tstname); + } + +} |