diff options
Diffstat (limited to 'src/jogl/classes/jogamp')
47 files changed, 2600 insertions, 1611 deletions
diff --git a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java index cc4e1b434..07029f143 100644 --- a/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java +++ b/src/jogl/classes/jogamp/opengl/GLAutoDrawableBase.java @@ -30,16 +30,15 @@ package jogamp.opengl; import java.io.PrintStream; -import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.WindowClosingProtocol; import javax.media.nativewindow.WindowClosingProtocol.WindowClosingMode; import javax.media.opengl.FPSCounter; import javax.media.opengl.GL; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; -import javax.media.opengl.GLAutoDrawableDelegate; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; @@ -49,6 +48,7 @@ import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.opengl.GLAutoDrawableDelegate; import com.jogamp.opengl.util.Animator; @@ -61,38 +61,36 @@ import com.jogamp.opengl.util.Animator; * @see GLWindow */ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { - public static final boolean DEBUG = Debug.debug("GLAutoDrawable"); + public static final boolean DEBUG = GLDrawableImpl.DEBUG; protected final GLDrawableHelper helper = new GLDrawableHelper(); protected final FPSCounterImpl fpsCounter = new FPSCounterImpl(); protected volatile GLDrawableImpl drawable; // volatile: avoid locking for read-only access protected GLContextImpl context; - protected final boolean ownDevice; + protected final boolean ownsDevice; protected int additionalCtxCreationFlags = 0; protected volatile boolean sendReshape = false; // volatile: maybe written by WindowManager thread w/o locking protected volatile boolean sendDestroy = false; // volatile: maybe written by WindowManager thread w/o locking /** - * @param drawable a valid {@link GLDrawableImpl}, may not be realized yet. - * @param context a valid {@link GLContextImpl}, may not be made current (created) yet. - * @param ownDevice pass <code>true</code> if {@link AbstractGraphicsDevice#close()} shall be issued, - * otherwise pass <code>false</code>. Closing the device is required in case - * the drawable is created w/ it's own new instance, e.g. offscreen drawables, - * and no further lifecycle handling is applied. + * @param drawable upstream {@link GLDrawableImpl} instance, may be null for lazy initialization + * @param context upstream {@link GLContextImpl} instance, may be null for lazy initialization + * @param ownsDevice pass <code>true</code> if {@link AbstractGraphicsDevice#close()} shall be issued, + * otherwise pass <code>false</code>. Closing the device is required in case + * the drawable is created w/ it's own new instance, e.g. offscreen drawables, + * and no further lifecycle handling is applied. */ - public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context, boolean ownDevice) { + public GLAutoDrawableBase(GLDrawableImpl drawable, GLContextImpl context, boolean ownsDevice) { this.drawable = drawable; this.context = context; - this.ownDevice = ownDevice; + this.ownsDevice = ownsDevice; resetFPSCounter(); } + /** Returns the recursive lock object of the upstream implementation, which synchronizes multithreaded access. */ protected abstract RecursiveLock getLock(); - /** Returns the delegated GLDrawable */ - public final GLDrawable getDelegatedDrawable() { return drawable; } - /** Default implementation to handle repaint events from the windowing system */ protected final void defaultWindowRepaintOp() { final GLDrawable _drawable = drawable; @@ -103,29 +101,43 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } } - /** Default implementation to handle resize events from the windowing system */ - protected final void defaultWindowResizedOp() { - final GLDrawable _drawable = drawable; + /** Default implementation to handle resize events from the windowing system. All required locks are being claimed. */ + protected final void defaultWindowResizedOp(int newWidth, int newHeight) throws NativeWindowException, GLException { + GLDrawableImpl _drawable = drawable; if( null!=_drawable ) { if(DEBUG) { - System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+getWidth()+"x"+getHeight()+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle())); + System.err.println("GLAutoDrawableBase.sizeChanged: ("+Thread.currentThread().getName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle())); + } + if( ! _drawable.getChosenGLCapabilities().isOnscreen() ) { + final RecursiveLock _lock = getLock(); + _lock.lock(); + try { + final GLDrawableImpl _drawableNew = GLDrawableHelper.resizeOffscreenDrawable(_drawable, context, newWidth, newHeight); + if(_drawable != _drawableNew) { + // write back + _drawable = _drawableNew; + drawable = _drawableNew; + } + } finally { + _lock.unlock(); + } } sendReshape = true; // async if display() doesn't get called below, but avoiding deadlock if( _drawable.isRealized() ) { if( !_drawable.getNativeSurface().isSurfaceLockedByOtherThread() && !helper.isAnimatorAnimating() ) { display(); } - } + } } } - + /** * Default implementation to handle destroy notifications from the windowing system. * * <p> * If the {@link NativeSurface} does not implement {@link WindowClosingProtocol} * or {@link WindowClosingMode#DISPOSE_ON_CLOSE} is enabled (default), - * {@link #defaultDestroy()} is being called. + * a thread safe destruction is being induced. * </p> */ protected final void defaultWindowDestroyNotifyOp() { @@ -174,7 +186,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { ctrl.resume(); } } else if (null != ns && ns.isSurfaceLockedByOtherThread()) { - // surface is locked by another thread + // Surface is locked by another thread. // Flag that destroy should be performed on the next // attempt to display. sendDestroy = true; // async, but avoiding deadlock @@ -225,7 +237,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } _drawable.setRealized(false); } - if( ownDevice ) { + if( ownsDevice ) { _drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getDevice().close(); } } @@ -238,7 +250,6 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { _lock.lock(); try { if(drawable!=null && context != null) { - drawable.swapBuffers(); helper.invokeGL(drawable, context, defaultSwapAction, defaultInitAction); } } finally { @@ -276,7 +287,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { destroy(); return; } - final RecursiveLock _lock = getLock(); + final RecursiveLock _lock = getLock(); _lock.lock(); try { if( null != context ) { @@ -295,6 +306,11 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { } } ; @Override + public final GLDrawable getDelegatedDrawable() { + return drawable; + } + + @Override public final GLContext getContext() { return context; } @@ -305,7 +321,7 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { lock.lock(); try { final GLContext oldCtx = context; - final boolean newCtxCurrent = helper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); + final boolean newCtxCurrent = GLDrawableHelper.switchContext(drawable, oldCtx, newCtx, additionalCtxCreationFlags); context=(GLContextImpl)newCtx; if(newCtxCurrent) { context.makeCurrent(); @@ -529,4 +545,10 @@ public abstract class GLAutoDrawableBase implements GLAutoDrawable, FPSCounter { final GLDrawable _drawable = drawable; return null != _drawable ? _drawable.getHandle() : 0; } + + @Override + public String toString() { + return getClass().getSimpleName()+"[ \n\tHelper: " + helper + ", \n\tDrawable: " + drawable + + ", \n\tContext: " + context + /** ", \n\tWindow: "+window+ ", \n\tFactory: "+factory+ */ "]"; + } } diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index e82756022..050c619fd 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -47,6 +47,7 @@ import java.util.Map; import com.jogamp.common.os.DynamicLookupHelper; import com.jogamp.common.util.ReflectionUtil; +import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.FunctionAddressResolver; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLNameResolver; @@ -85,6 +86,7 @@ public abstract class GLContextImpl extends GLContext { private String glRenderer; private String glRendererLowerCase; + private String glVersion; // Tracks creation and initialization of buffer objects to avoid // repeated glGet calls upon glMapBuffer operations @@ -126,6 +128,9 @@ public abstract class GLContextImpl extends GLContext { GLContextShareSet.synchronizeBufferObjectSharing(shareWith, this); this.drawable = drawable; + if(null != drawable) { + drawable.associateContext(this, true); + } this.drawableRead = drawable; this.glDebugHandler = new GLDebugMessageHandler(this); @@ -205,8 +210,10 @@ public abstract class GLContextImpl extends GLContext { if(!setWriteOnly || drawableRead==drawable) { // if !setWriteOnly || !explicitReadDrawable drawableRead = (GLDrawableImpl) readWrite; } - final GLDrawable old = drawable; + final GLDrawableImpl old = drawable; + old.associateContext(this, false); drawable = (GLDrawableImpl) readWrite ; + drawable.associateContext(this, true); if(lockHeld) { makeCurrent(); } @@ -272,7 +279,7 @@ public abstract class GLContextImpl extends GLContext { if( actualRelease ) { if( !inDestruction ) { try { - drawable.contextMadeCurrent(this, false); + contextMadeCurrent(false); } catch (Throwable t) { drawableContextMadeCurrentException = t; } @@ -331,7 +338,8 @@ public abstract class GLContextImpl extends GLContext { makeCurrent(); } try { - drawable.contextRealized(this, false); + contextRealized(false); + drawable.associateContext(this, false); } catch (Throwable t) { drawableContextRealizedException = t; } @@ -514,19 +522,17 @@ public abstract class GLContextImpl extends GLContext { gl = gl.getContext().setGL( GLPipelineFactory.create("javax.media.opengl.Trace", null, gl, new Object[] { System.err } ) ); } - drawable.contextRealized(this, true); + contextRealized(true); if(DEBUG || TRACE_SWITCH) { System.err.println(getThreadName() +": GLContext.ContextSwitch: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - switch - CONTEXT_CURRENT_NEW - "+lock); } - } else { - drawable.contextMadeCurrent(this, true); - - if(TRACE_SWITCH) { - System.err.println(getThreadName() +": GLContext.ContextSwitch: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - switch - CONTEXT_CURRENT - "+lock); - } + } else if(TRACE_SWITCH) { + System.err.println(getThreadName() +": GLContext.ContextSwitch: obj " + toHexString(hashCode()) + ", ctx "+toHexString(contextHandle)+" - switch - CONTEXT_CURRENT - "+lock); } + contextMadeCurrent(true); + /* FIXME: refactor dependence on Java 2D / JOGL bridge // Try cleaning up any stale server-side OpenGL objects @@ -609,6 +615,20 @@ public abstract class GLContextImpl extends GLContext { protected abstract void makeCurrentImpl() throws GLException; /** + * @see GLDrawableImpl#contextRealized(GLContext, boolean) + */ + protected void contextRealized(boolean realized) { + drawable.contextRealized(this, realized); + } + + /** + * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean) + */ + protected void contextMadeCurrent(boolean current) { + drawable.contextMadeCurrent(this, current); + } + + /** * Platform dependent entry point for context creation.<br> * * This method is called from {@link #makeCurrentWithinLock()} .. {@link #makeCurrent()} .<br> @@ -934,52 +954,43 @@ public abstract class GLContextImpl extends GLContext { /** * If major > 0 || minor > 0 : Use passed values, determined at creation time - * If major==0 && minor == 0 : Use GL_VERSION * Otherwise .. don't touch .. */ private final void setContextVersion(int major, int minor, int ctp, boolean setVersionString) { - if (0==ctp) { + if ( 0 == ctp ) { throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp)); } - if(major>0 || minor>0) { - if (!GLContext.isValidGLVersion(major, minor)) { - GLException e = new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp)); - throw e; - } - ctxMajorVersion = major; - ctxMinorVersion = minor; - ctxOptions = ctp; - if(setVersionString) { - ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, getGL().glGetString(GL.GL_VERSION)); - } - return; + + if (!GLContext.isValidGLVersion(major, minor)) { + throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctp)); } - - if(major==0 && minor==0) { - String versionStr = getGL().glGetString(GL.GL_VERSION); - if(null==versionStr) { - throw new GLException("GL_VERSION is NULL: "+this); - } - ctxOptions = ctp; - - // Set version - GLVersionNumber version = new GLVersionNumber(versionStr); + ctxMajorVersion = major; + ctxMinorVersion = minor; + ctxOptions = ctp; + if(setVersionString) { + ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, getGL().glGetString(GL.GL_VERSION)); + } + } + + private static final VersionNumber getGLVersionNumber(int ctp, String glVersionStr) { + if( null != glVersionStr ) { + final GLVersionNumber version = new GLVersionNumber(glVersionStr); if (version.isValid()) { - ctxMajorVersion = version.getMajor(); - ctxMinorVersion = version.getMinor(); - // We cannot promote a non ARB context to >= 3.1, - // reduce it to 3.0 then. - if ( ( ctxMajorVersion>3 || ctxMajorVersion==3 && ctxMinorVersion>=1 ) - && 0 == (ctxOptions & CTX_IS_ARB_CREATED) ) { - ctxMajorVersion = 3; - ctxMinorVersion = 0; - } - if(setVersionString) { - ctxVersionString = getGLVersion(ctxMajorVersion, ctxMinorVersion, ctxOptions, versionStr); - } - return; + int major = version.getMajor(); + int minor = version.getMinor(); + // We cannot promote a non ARB context to >= 3.1, + // reduce it to 3.0 then. + if ( 0 == (ctp & CTX_IS_ARB_CREATED) && + ( major > 3 || major == 3 && minor >= 1 ) ) { + major = 3; + minor = 0; + } + if ( GLContext.isValidGLVersion(major, minor) ) { + return new VersionNumber(major, minor, 0); + } } } + return null; } //---------------------------------------------------------------------- @@ -1019,14 +1030,18 @@ public abstract class GLContextImpl extends GLContext { /** * Pbuffer support; given that this is a GLContext associated with a * pbuffer, binds this pbuffer to its texture target. + * @throws GLException if not implemented (default) + * @deprecated use FBO/GLOffscreenAutoDrawable instead of pbuffer */ - public abstract void bindPbufferToTexture(); + public void bindPbufferToTexture() { throw new GLException("not implemented"); } /** * Pbuffer support; given that this is a GLContext associated with a * pbuffer, releases this pbuffer from its texture target. + * @throws GLException if not implemented (default) + * @deprecated use FBO/GLOffscreenAutoDrawable instead of pbuffer */ - public abstract void releasePbufferFromTexture(); + public void releasePbufferFromTexture() { throw new GLException("not implemented"); } public abstract ByteBuffer glAllocateMemoryNV(int arg0, float arg1, float arg2, float arg3); @@ -1064,7 +1079,7 @@ public abstract class GLContextImpl extends GLContext { table.reset(getDrawableImpl().getGLDynamicLookupHelper() ); } - private final boolean initGLRendererStrings() { + private final boolean initGLRendererAndGLVersionStrings() { final GLDynamicLookupHelper glDynLookupHelper = getDrawableImpl().getGLDynamicLookupHelper(); final long _glGetString = glDynLookupHelper.dynamicLookupFunction("glGetString"); if(0 == _glGetString) { @@ -1083,14 +1098,27 @@ public abstract class GLContextImpl extends GLContext { Thread.dumpStack(); } return false; - } else { - glRenderer = _glRenderer; - glRendererLowerCase = glRenderer.toLowerCase(); - return true; } + glRenderer = _glRenderer; + glRendererLowerCase = glRenderer.toLowerCase(); + + final String _glVersion = glGetStringInt(GL.GL_VERSION, _glGetString); + if(null == _glVersion) { + // FIXME + if(DEBUG) { + System.err.println("Warning: GL_VERSION is NULL."); + Thread.dumpStack(); + } + return false; + } + glVersion = _glVersion; + return true; } } + protected final String getGLVersionString() { + return glVersion; + } protected final String getGLRendererString(boolean lowerCase) { return lowerCase ? glRendererLowerCase : glRenderer; } @@ -1128,17 +1156,44 @@ public abstract class GLContextImpl extends GLContext { final AbstractGraphicsConfiguration aconfig = drawable.getNativeSurface().getGraphicsConfiguration(); final AbstractGraphicsDevice adevice = aconfig.getScreen().getDevice(); - if( !initGLRendererStrings() && DEBUG) { - System.err.println("Warning: intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)); + { + final boolean initGLRendererAndGLVersionStringsOK = initGLRendererAndGLVersionStrings(); + if(DEBUG) { + if( !initGLRendererAndGLVersionStringsOK ) { + System.err.println("Warning: setGLFunctionAvailability: intialization of GL renderer strings failed. "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)); + } else { + System.err.println(getThreadName() + ": GLContext.setGLFuncAvail: Given "+adevice+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion)); + } + } } if(!isCurrentContextHardwareRasterizer()) { ctxProfileBits |= GLContext.CTX_IMPL_ACCEL_SOFT; } - + + // Pick the version from the GL-version string, + // if smaller _or_ given major == 0. + final VersionNumber glVersionNumber; + { + final VersionNumber setGLVersionNumber = new VersionNumber(major, minor, 0); + final VersionNumber strGLVersionNumber = getGLVersionNumber(ctxProfileBits, glVersion); + if( null != strGLVersionNumber && ( strGLVersionNumber.compareTo(setGLVersionNumber) <= 0 || 0 == major ) ) { + glVersionNumber = strGLVersionNumber; + major = glVersionNumber.getMajor(); + minor = glVersionNumber.getMinor(); + } else { + glVersionNumber = setGLVersionNumber; + } + } + if ( !GLContext.isValidGLVersion(major, minor) ) { + throw new GLException("Invalid GL Version "+major+"."+minor+", ctp "+toHexString(ctxProfileBits)+", "+glVersion+", "+glVersionNumber); + } + if( 2 > major ) { // there is no ES2-compat for a profile w/ major < 2 + ctxProfileBits &= ~GLContext.CTX_IMPL_ES2_COMPAT; + } contextFQN = getContextFQN(adevice, major, minor, ctxProfileBits); if (DEBUG) { - System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, null)); + System.err.println(getThreadName() + ": GLContext.setGLFuncAvail.0 validated FQN: "+contextFQN+" - "+GLContext.getGLVersion(major, minor, ctxProfileBits, glVersion) + ", "+glVersionNumber); } // @@ -1201,6 +1256,10 @@ public abstract class GLContextImpl extends GLContext { ctxProfileBits |= CTX_IMPL_FBO; } + if(FORCE_NO_FBO_SUPPORT) { + ctxProfileBits &= ~CTX_IMPL_FBO ; + } + // // Set GL Version (complete w/ version string) // diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 2f2bf5961..4f965f620 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -48,18 +48,21 @@ import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.MutableSurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; -import javax.media.opengl.GLCapabilities; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; +import javax.media.opengl.GLFBODrawable; +import javax.media.opengl.GLOffscreenAutoDrawable; import javax.media.opengl.GLPbuffer; import javax.media.opengl.GLProfile; import com.jogamp.nativewindow.MutableGraphicsConfiguration; +import com.jogamp.nativewindow.DelegatedUpstreamSurfaceHookWithSurfaceSize; +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; /** Extends GLDrawableFactory with a few methods for handling @@ -67,6 +70,7 @@ import com.jogamp.nativewindow.MutableGraphicsConfiguration; Independent Bitmaps on Windows, pixmaps on X11). Direct access to these GLDrawables is not supplied directly to end users, though they may be instantiated by the GLJPanel implementation. */ +@SuppressWarnings("deprecation") public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { protected static final boolean DEBUG = GLDrawableImpl.DEBUG; @@ -141,55 +145,53 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true); if(null != ols) { // layered surface -> Offscreen/[FBO|PBuffer] - final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable(); - chosenCapsMod.setOnscreen(false); - chosenCapsMod.setDoubleBuffered(false); - /* if( isFBOAvailable ) { // FIXME JAU: FBO n/a yet - chosenCapsMod.setFBO(true); - } else */ - if( canCreateGLPbuffer(adevice) ) { - chosenCapsMod.setPBuffer(true); - } else { - chosenCapsMod.setFBO(false); - chosenCapsMod.setPBuffer(false); + final boolean isPbufferAvailable = canCreateGLPbuffer(adevice) ; + if(!isPbufferAvailable && !isFBOAvailable) { + throw new GLException("Neither FBO nor Pbuffer is available for "+target); } + final GLCapabilitiesImmutable chosenCapsMod = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(chosenCaps, isFBOAvailable, isPbufferAvailable); config.setChosenCapabilities(chosenCapsMod); + ols.setChosenCapabilities(chosenCapsMod); if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer: "+target); + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer"); + System.err.println("chosenCaps: "+chosenCaps); + System.err.println("chosenCapsMod: "+chosenCapsMod); + System.err.println("OffscreenLayerSurface: **** "+ols); + System.err.println("Target: **** "+target); + Thread.dumpStack(); } if( ! ( target instanceof MutableSurface ) ) { throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target); } - if( ((GLCapabilitiesImmutable)config.getRequestedCapabilities()).isFBO() && isFBOAvailable ) { - // FIXME JAU: Need to revise passed MutableSurface to work w/ FBO .. - final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(target); - result = new GLFBODrawableImpl(this, dummyDrawable, target, target.getWidth(), target.getHeight(), 0 /* textureUnit */); + if( chosenCapsMod.isFBO() && isFBOAvailable ) { + // target surface is already a native one + result = createFBODrawableImpl(target, chosenCapsMod, 0); } else { result = createOffscreenDrawableImpl(target); } } else if(chosenCaps.isOnscreen()) { // onscreen + final GLCapabilitiesImmutable chosenCapsMod = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(chosenCaps); + config.setChosenCapabilities(chosenCapsMod); if(DEBUG) { System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target); } result = createOnscreenDrawableImpl(target); } else { // offscreen - final GLCapabilitiesImmutable reqCaps = (GLCapabilitiesImmutable)config.getRequestedCapabilities(); if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable, FBO req / chosen - avail, PBuffer: "+reqCaps.isFBO()+" / "+chosenCaps.isFBO()+" - "+isFBOAvailable+", "+chosenCaps.isPBuffer()+": "+target); + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable, FBO chosen / avail, PBuffer: "+ + chosenCaps.isFBO()+" / "+isFBOAvailable+", "+chosenCaps.isPBuffer()+": "+target); } if( ! ( target instanceof MutableSurface ) ) { - throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen: "+target); + throw new IllegalArgumentException("Passed NativeSurface must implement MutableSurface for offscreen: "+target); } - if( reqCaps.isFBO() && isFBOAvailable ) { - // FIXME JAU: Need to revise passed MutableSurface to work w/ FBO .. - final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(target); - result = new GLFBODrawableImpl(this, dummyDrawable, target, target.getWidth(), target.getHeight(), 0 /* textureUnit */); + if( chosenCaps.isFBO() && isFBOAvailable ) { + // need to hook-up a native dummy surface since source may not have + final ProxySurface dummySurface = createDummySurfaceImpl(adevice, true, chosenCaps, null, 64, 64); + dummySurface.setUpstreamSurfaceHook(new DelegatedUpstreamSurfaceHookWithSurfaceSize(dummySurface.getUpstreamSurfaceHook(), target)); + result = createFBODrawableImpl(dummySurface, chosenCaps, 0); } else { - final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable(); - chosenCapsMod.setDoubleBuffered(false); - config.setChosenCapabilities(chosenCapsMod); result = createOffscreenDrawableImpl(target); } } @@ -211,7 +213,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { //--------------------------------------------------------------------------- // - // PBuffer Offscreen GLDrawable construction + // PBuffer Offscreen GLAutoDrawable construction // @Override @@ -239,7 +241,8 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { GLDrawableImpl drawable = null; device.lock(); try { - drawable = (GLDrawableImpl) createGLDrawable( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, width, height, null) ); + drawable = createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, + new UpstreamSurfaceHookMutableSize(width, height) ) ); if(null != drawable) { drawable.setRealized(true); } @@ -247,10 +250,7 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { device.unlock(); } - if(null==drawable) { - throw new GLException("Could not create Pbuffer drawable for: "+device+", "+capsChosen+", "+width+"x"+height); - } - return new GLPbufferImpl( drawable, shareWith, true); + return new GLPbufferImpl( drawable, (GLContextImpl) drawable.createContext(shareWith) ); } //--------------------------------------------------------------------------- @@ -258,6 +258,29 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { // Offscreen GLDrawable construction // + public final boolean canCreateFBO(AbstractGraphicsDevice deviceReq, GLProfile glp) { + AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq); + if(null == device) { + throw new GLException("No shared device for requested: "+deviceReq); + } + return GLContext.isFBOAvailable(device, glp); + } + + @Override + public GLOffscreenAutoDrawable createOffscreenAutoDrawable(AbstractGraphicsDevice deviceReq, + GLCapabilitiesImmutable capsRequested, + GLCapabilitiesChooser chooser, + int width, int height, + GLContext shareWith) { + final GLDrawable drawable = createOffscreenDrawable( deviceReq, capsRequested, chooser, width, height ); + drawable.setRealized(true); + final GLContext context = drawable.createContext(shareWith); + if(drawable instanceof GLFBODrawableImpl) { + return new GLOffscreenAutoDrawableImpl.FBOImpl( (GLFBODrawableImpl)drawable, context, null, null ); + } + return new GLOffscreenAutoDrawableImpl( drawable, context, null, null); + } + @Override public GLDrawable createOffscreenDrawable(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable capsRequested, @@ -271,32 +294,34 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { throw new GLException("No shared device for requested: "+deviceReq); } - if( capsRequested.isFBO() && GLContext.isFBOAvailable(device, capsRequested.getGLProfile()) ) { + final GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(capsRequested, + GLContext.isFBOAvailable(device, capsRequested.getGLProfile()), + canCreateGLPbuffer(device)); + + if( capsChosen.isFBO() ) { device.lock(); try { - return createFBODrawableImpl(device, capsRequested, chooser, width, height); + final ProxySurface dummySurface = createDummySurfaceImpl(device, true, capsRequested, null, width, height); + final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(dummySurface); + return new GLFBODrawableImpl.ResizeableImpl(this, dummyDrawable, dummySurface, capsChosen, 0); } finally { device.unlock(); } } - final GLCapabilitiesImmutable capsChosen = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(capsRequested, false, canCreateGLPbuffer(device)); device.lock(); try { - return createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, width, height, null) ); + return createOffscreenDrawableImpl( createMutableSurfaceImpl(device, true, capsChosen, capsRequested, chooser, + new UpstreamSurfaceHookMutableSize(width, height) ) ); } finally { device.unlock(); } } - /** Creates a platform independent offscreen FBO GLDrawable implementation */ - protected GLDrawable createFBODrawableImpl(AbstractGraphicsDevice device, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, - int initialWidth, int initialHeight) { - final GLCapabilitiesImmutable dummyCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps); - final NativeSurface dummySurface = createDummySurfaceImpl(device, true, dummyCaps, null, 64, 64); + /** Creates a platform independent FBO offscreen GLDrawable */ + protected GLFBODrawable createFBODrawableImpl(NativeSurface dummySurface, GLCapabilitiesImmutable fboCaps, int textureUnit) { final GLDrawableImpl dummyDrawable = createOnscreenDrawableImpl(dummySurface); - - return new GLFBODrawableImpl(this, dummyDrawable, dummySurface, initialWidth, initialHeight, 0 /* textureUnit */); + return new GLFBODrawableImpl(this, dummyDrawable, dummySurface, fboCaps, textureUnit); } /** Creates a platform dependent offscreen pbuffer/pixmap GLDrawable implementation */ @@ -316,15 +341,13 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { * @param capsChosen * @param capsRequested * @param chooser the custom chooser, may be null for default - * @param width the initial width - * @param height the initial height - * @param lifecycleHook optional control of the surface's lifecycle + * @param upstreamHook surface size information and optional control of the surface's lifecycle * @return the created {@link MutableSurface} instance w/o defined surface handle */ protected abstract ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook); + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook); /** * A dummy surface is not visible on screen and will not be used to render directly to, @@ -339,9 +362,9 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { * @param width the initial width * @param height the initial height * - * @return the created {@link MutableSurface} instance w/o defined surface handle + * @return the created {@link ProxySurface} instance w/o defined surface handle but platform specific {@link UpstreamSurfaceHook}. */ - public NativeSurface createDummySurface(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, + public ProxySurface createDummySurface(AbstractGraphicsDevice deviceReq, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) { final AbstractGraphicsDevice device = getOrCreateSharedDevice(deviceReq); if(null == device) { @@ -367,9 +390,11 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { * otherwise <code>device</code> instance is used as-is. * @param requestedCaps * @param chooser the custom chooser, may be null for default - * @param width the initial width - * @param height the initial height - * @return the created {@link MutableSurface} instance w/o defined surface handle + * @param width the initial width as returned by {@link NativeSurface#getWidth()}, not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getHeight()}, not the actual dummy surface height, + * The latter is platform specific and small + * @return the created {@link ProxySurface} instance w/o defined surface handle but platform specific {@link UpstreamSurfaceHook}. */ public abstract ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice device, boolean createNewDevice, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height); diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java index 090c5fe69..bdf0b6d74 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableHelper.java @@ -43,12 +43,19 @@ package jogamp.opengl; import java.util.ArrayList; import java.util.HashSet; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GLAnimatorControl; import javax.media.opengl.GLAutoDrawable; +import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLEventListener; import javax.media.opengl.GLException; +import javax.media.opengl.GLFBODrawable; import javax.media.opengl.GLRunnable; import com.jogamp.opengl.util.Animator; @@ -108,24 +115,27 @@ public class GLDrawableHelper { /** * Associate a new context to the drawable and also propagates the context/drawable switch by * calling {@link GLContext#setGLDrawable(GLDrawable, boolean) newCtx.setGLDrawable(drawable, true);}. - * <p> - * If the old context's drawable was an {@link GLAutoDrawable}, it's reference to the given drawable - * is being cleared by calling - * {@link GLAutoDrawable#setContext(GLContext) ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null)}. - * </p> * <p> * If the old or new context was current on this thread, it is being released before switching the drawable. * </p> + * <p> + * Be aware that the old context is still bound to the drawable, + * and that one context can only bound to one drawable at one time! + * </p> + * <p> + * No locking is being performed on the drawable, caller is required to take care of it. + * </p> * * @param drawable the drawable which context is changed - * @param newCtx the new context * @param oldCtx the old context - * @return true if the newt context was current, otherwise false + * @param newCtx the new context + * @param newCtxCreationFlags additional creation flags if newCtx is not null and not been created yet, see {@link GLContext#setContextCreationFlags(int)} + * @return true if the new context was current, otherwise false * * @see GLAutoDrawable#setContext(GLContext) */ - public final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int additionalCtxCreationFlags) { - if(null != oldCtx && oldCtx.isCurrent()) { + public static final boolean switchContext(GLDrawable drawable, GLContext oldCtx, GLContext newCtx, int newCtxCreationFlags) { + if( null != oldCtx && oldCtx.isCurrent() ) { oldCtx.release(); } final boolean newCtxCurrent; @@ -134,17 +144,135 @@ public class GLDrawableHelper { if(newCtxCurrent) { newCtx.release(); } - newCtx.setContextCreationFlags(additionalCtxCreationFlags); + newCtx.setContextCreationFlags(newCtxCreationFlags); newCtx.setGLDrawable(drawable, true); // propagate context/drawable switch } else { newCtxCurrent = false; } - if(null!=oldCtx && oldCtx.getGLDrawable() instanceof GLAutoDrawable) { - ((GLAutoDrawable)oldCtx.getGLDrawable()).setContext(null); - } return newCtxCurrent; } + /** + * If the drawable is not realized, OP is a NOP. + * <ul> + * <li>release context if current</li> + * <li>destroy old drawable</li> + * <li>create new drawable</li> + * <li>attach new drawable to context</li> + * <li>make context current, if it was current</li> + * </ul> + * <p> + * No locking is being performed, caller is required to take care of it. + * </p> + * + * @param drawable + * @param context maybe null + * @return the new drawable + */ + public static final GLDrawableImpl recreateGLDrawable(GLDrawableImpl drawable, GLContext context) { + if( ! drawable.isRealized() ) { + return drawable; + } + final boolean contextCurrent = null != context && context.isCurrent(); + final GLDrawableFactory factory = drawable.getFactory(); + final NativeSurface surface = drawable.getNativeSurface(); + final ProxySurface proxySurface = (surface instanceof ProxySurface) ? (ProxySurface)surface : null; + + if(contextCurrent) { + context.release(); + } + + if(null != proxySurface) { + proxySurface.enableUpstreamSurfaceHookLifecycle(false); + } + try { + drawable.setRealized(false); + drawable = (GLDrawableImpl) factory.createGLDrawable(surface); // [2] + drawable.setRealized(true); + } finally { + if(null != proxySurface) { + proxySurface.enableUpstreamSurfaceHookLifecycle(true); + } + } + + if(null != context) { + context.setGLDrawable(drawable, true); // re-association + } + + if(contextCurrent) { + context.makeCurrent(); + } + return drawable; + } + + /** + * Performs resize operation on the given drawable, assuming it is offscreen. + * <p> + * The {@link GLDrawableImpl}'s {@link NativeSurface} is being locked during operation. + * In case the holder is an auto drawable or similar, it's lock shall be claimed by the caller. + * </p> + * <p> + * May recreate the drawable via {@link #recreateGLDrawable(GLDrawableImpl, GLContext)} + * in case of a a pbuffer- or pixmap-drawable. + * </p> + * <p> + * FBO drawables are resized w/o drawable destruction. + * </p> + * <p> + * Offscreen resize operation is validated w/ drawable size in the end. + * An exception is thrown if not successful. + * </p> + * + * @param drawable + * @param context + * @param newWidth the new width, it's minimum is capped to 1 + * @param newHeight the new height, it's minimum is capped to 1 + * @return the new drawable in case of an pbuffer/pixmap drawable, otherwise the passed drawable is being returned. + * @throws NativeWindowException is drawable is not offscreen or it's surface lock couldn't be claimed + * @throws GLException may be thrown a resize operation + */ + public static final GLDrawableImpl resizeOffscreenDrawable(GLDrawableImpl drawable, GLContext context, int newWidth, int newHeight) + throws NativeWindowException, GLException + { + if(drawable.getChosenGLCapabilities().isOnscreen()) { + throw new NativeWindowException("Drawable is not offscreen: "+drawable); + } + final NativeSurface ns = drawable.getNativeSurface(); + final int lockRes = ns.lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock surface of drawable: "+drawable); + } + try { + if(0>=newWidth) { newWidth = 1; } + if(0>=newHeight) { newHeight = 1; } + // propagate new size + if(ns instanceof ProxySurface) { + final ProxySurface ps = (ProxySurface) ns; + final UpstreamSurfaceHook ush = ps.getUpstreamSurfaceHook(); + if(ush instanceof UpstreamSurfaceHook.MutableSize) { + ((UpstreamSurfaceHook.MutableSize)ush).setSize(newWidth, newHeight); + } else if(DEBUG) { // we have to assume UpstreamSurfaceHook contains the new size already, hence size check @ bottom + System.err.println("GLDrawableHelper.resizeOffscreenDrawable: Drawable's offscreen ProxySurface n.a. UpstreamSurfaceHook.MutableSize, but "+ush.getClass().getName()+": "+ush); + } + } else if(DEBUG) { // we have to assume surface contains the new size already, hence size check @ bottom + System.err.println("GLDrawableHelper.resizeOffscreenDrawable: Drawable's offscreen surface n.a. ProxySurface, but "+ns.getClass().getName()+": "+ns); + } + if(drawable instanceof GLFBODrawable) { + if( null != context && context.isCreated() ) { + ((GLFBODrawable) drawable).resetSize(context.getGL()); + } + } else { + drawable = GLDrawableHelper.recreateGLDrawable(drawable, context); + } + } finally { + ns.unlockSurface(); + } + if(drawable.getWidth() != newWidth || drawable.getHeight() != newHeight) { + throw new InternalError("Incomplete resize operation: expected "+newWidth+"x"+newHeight+", has: "+drawable); + } + return drawable; + } + public final void addGLEventListener(GLEventListener listener) { addGLEventListener(-1, listener); } @@ -196,15 +324,11 @@ public class GLDrawableHelper { } } - private final boolean init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) { - if(listenersToBeInit.remove(l)) { - l.init(drawable); - if(sendReshape) { - reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false /* checkInit */); - } - return true; + private final void init(GLEventListener l, GLAutoDrawable drawable, boolean sendReshape) { + l.init(drawable); + if(sendReshape) { + reshape(l, drawable, 0, 0, drawable.getWidth(), drawable.getHeight(), true /* setViewport */, false /* checkInit */); } - return false; } /** The default init action to be called once after ctx is being created @ 1st makeCurrent(). */ @@ -214,14 +338,11 @@ public class GLDrawableHelper { for (int i=0; i < _listeners.size(); i++) { final GLEventListener listener = _listeners.get(i) ; - // If make current ctx, invoked by invokGL(..), results in a new ctx, init gets called. + // If make ctx current, invoked by invokGL(..), results in a new ctx, init gets called. // This may happen not just for initial setup, but for ctx recreation due to resource change (drawable/window), - // hence the must always be initialized unconditional. - listenersToBeInit.add(listener); - - if ( ! init( listener, drawable, true /* sendReshape */) ) { - throw new GLException("GLEventListener "+listener+" already initialized: "+drawable); - } + // hence it must be called unconditional, always. + listenersToBeInit.remove(listener); // remove if exist, avoiding dbl init + init( listener, drawable, true /* sendReshape */); } } } @@ -239,7 +360,9 @@ public class GLDrawableHelper { final GLEventListener listener = _listeners.get(i) ; // GLEventListener may need to be init, // in case this one is added after the realization of the GLAutoDrawable - init( listener, drawable, true /* sendReshape */) ; + if( listenersToBeInit.remove(listener) ) { + init( listener, drawable, true /* sendReshape */) ; + } listener.display(drawable); } } @@ -251,7 +374,9 @@ public class GLDrawableHelper { // GLEventListener may need to be init, // in case this one is added after the realization of the GLAutoDrawable synchronized(listenersLock) { - init( listener, drawable, false /* sendReshape */) ; + if( listenersToBeInit.remove(listener) ) { + init( listener, drawable, false /* sendReshape */) ; + } } } if(setViewport) { diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index abf2bf557..311690f1d 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -43,6 +43,7 @@ package jogamp.opengl; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; +import javax.media.opengl.GL; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; @@ -76,31 +77,46 @@ public abstract class GLDrawableImpl implements GLDrawable { if( !realized ) { return; // destroyed already } - final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)surface.getGraphicsConfiguration().getChosenCapabilities(); - if ( caps.getDoubleBuffered() ) { - if(!surface.surfaceSwap()) { - int lockRes = lockSurface(); // it's recursive, so it's ok within [makeCurrent .. release] - if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { - return; + int lockRes = lockSurface(); // it's recursive, so it's ok within [makeCurrent .. release] + if (NativeSurface.LOCK_SURFACE_NOT_READY == lockRes) { + return; + } + try { + if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) { + updateHandle(); + } + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)surface.getGraphicsConfiguration().getChosenCapabilities(); + if ( caps.getDoubleBuffered() ) { + if(!surface.surfaceSwap()) { + swapBuffersImpl(true); } - try { - if (NativeSurface.LOCK_SURFACE_CHANGED == lockRes) { - updateHandle(); - } - swapBuffersImpl(); - } finally { - unlockSurface(); + } else { + final GLContext ctx = GLContext.getCurrent(); + if(null!=ctx && ctx.getGLDrawable()==this) { + ctx.getGL().glFlush(); } + swapBuffersImpl(false); } - } else { - GLContext ctx = GLContext.getCurrent(); - if(null!=ctx && ctx.getGLDrawable()==this) { - ctx.getGL().glFinish(); - } - } + } finally { + unlockSurface(); + } surface.surfaceUpdated(this, surface, System.currentTimeMillis()); } - protected abstract void swapBuffersImpl(); + + /** + * Platform and implementation depending surface swap. + * <p>The surface is locked.</p> + * <p> + * If <code>doubleBuffered</code> is <code>true</code>, + * an actual platform dependent surface swap shall be executed. + * </p> + * <p> + * If <code>doubleBuffered</code> is <code>false</code>, + * {@link GL#glFlush()} has been called already and + * the implementation may execute implementation specific code. + * </p> + */ + protected abstract void swapBuffersImpl(boolean doubleBuffered); public final static String toHexString(long hex) { return "0x" + Long.toHexString(hex); @@ -181,6 +197,9 @@ public abstract class GLDrawableImpl implements GLDrawable { System.err.println(getThreadName() + ": setRealized: "+getClass().getName()+" "+this.realized+" == "+realizedArg); } } + /** + * Platform specific realization of drawable + */ protected abstract void setRealizedImpl(); /** @@ -189,7 +208,7 @@ public abstract class GLDrawableImpl implements GLDrawable { * If <code>realized</code> is <code>true</code>, the context has just been created and made current. * </p> * <p> - * If <code>realized</code> is <code>false</code>, the context is still current and will be release and destroyed after this method returns. + * If <code>realized</code> is <code>false</code>, the context is still current and will be released and destroyed after this method returns. * </p> * <p> * @see #contextMadeCurrent(GLContext, boolean) @@ -199,18 +218,27 @@ public abstract class GLDrawableImpl implements GLDrawable { /** * Callback for special implementations, allowing GLContext to trigger GL related lifecycle: <code>makeCurrent</code>, <code>release</code>. * <p> - * Will not be called if {@link #contextRealized(GLContext, boolean)} has been triggered. - * </p> - * <p> * If <code>current</code> is <code>true</code>, the context has just been made current. * </p> * <p> * If <code>current</code> is <code>false</code>, the context is still current and will be release after this method returns. * </p> + * <p> + * Note: Will also be called after {@link #contextRealized(GLContext, boolean) contextRealized(ctx, true)} + * but not at context destruction, i.e. {@link #contextRealized(GLContext, boolean) contextRealized(ctx, false)}. + * </p> * @see #contextRealized(GLContext, boolean) */ protected void contextMadeCurrent(GLContext glc, boolean current) { } + /** + * Callback for special implementations, allowing to associate bound context to this drawable (bound == true) + * or to remove such association (bound == false). + * @param ctx the just bounded or unbounded context + * @param bound if <code>true</code> create an association, otherwise remove it + */ + protected void associateContext(GLContext ctx, boolean bound) { } + /** Callback for special implementations, allowing GLContext to fetch a custom default render framebuffer. Defaults to zero.*/ protected int getDefaultDrawFramebuffer() { return 0; } /** Callback for special implementations, allowing GLContext to fetch a custom default read framebuffer. Defaults to zero. */ @@ -245,8 +273,8 @@ public abstract class GLDrawableImpl implements GLDrawable { public String toString() { return getClass().getSimpleName()+"[Realized "+isRealized()+ ",\n\tFactory "+getFactory()+ - ",\n\thandle "+toHexString(getHandle())+ - ",\n\tWindow "+getNativeSurface()+"]"; + ",\n\tHandle "+toHexString(getHandle())+ + ",\n\tSurface "+getNativeSurface()+"]"; } protected static String getThreadName() { diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index 03bc26cbc..de45466f3 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -1,142 +1,476 @@ package jogamp.opengl; import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GL; -import javax.media.opengl.GL2GL3; +import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; +import javax.media.opengl.GLFBODrawable; import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.opengl.FBObject; import com.jogamp.opengl.FBObject.Attachment; +import com.jogamp.opengl.FBObject.Colorbuffer; import com.jogamp.opengl.FBObject.TextureAttachment; /** - * Offscreen GLDrawable implementation using framebuffer object (FBO) - * as it's offscreen rendering mechanism. + * {@link FBObject} offscreen GLDrawable implementation, i.e. {@link GLFBODrawable}. + * <p> + * It utilizes the context lifecycle hook {@link #contextRealized(GLContext, boolean)} + * to initialize the {@link FBObject} instance. + * </p> + * <p> + * It utilizes the context current hook {@link #contextMadeCurrent(GLContext, boolean) contextMadeCurrent(context, true)} + * to {@link FBObject#bind(GL) bind} the FBO. + * </p> + * See {@link GLFBODrawable} for double buffering details. * * @see GLDrawableImpl#contextRealized(GLContext, boolean) * @see GLDrawableImpl#contextMadeCurrent(GLContext, boolean) * @see GLDrawableImpl#getDefaultDrawFramebuffer() * @see GLDrawableImpl#getDefaultReadFramebuffer() */ -public class GLFBODrawableImpl extends GLDrawableImpl { - final GLDrawableImpl parent; - final FBObject fbo; - int texUnit; - int samplesTexUnit = 0; - int width=0, height=0, samples=0; - - protected GLFBODrawableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, - NativeSurface surface, int initialWidth, int initialHeight, int textureUnit) { +public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { + protected static final boolean DEBUG = GLDrawableImpl.DEBUG || Debug.debug("FBObject"); + + private final GLDrawableImpl parent; + + private boolean initialized; + private int texUnit; + private int samples; + + private FBObject[] fbos; + private int fboIBack; // points to GL_BACK buffer + private int fboIFront; // points to GL_FRONT buffer + private FBObject pendingFBOReset = null; + private boolean fboBound; + private static final int bufferCount = 2; // number of FBOs for double buffering. TODO: Possible to configure! + + // private DoubleBufferMode doubleBufferMode; // TODO: Add or remove TEXTURE (only) DoubleBufferMode support + + private SwapBufferContext swapBufferContext; + + public static interface SwapBufferContext { + public void swapBuffers(boolean doubleBuffered); + } + + protected GLFBODrawableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, NativeSurface surface, + GLCapabilitiesImmutable fboCaps, int textureUnit) { super(factory, surface, false); + this.initialized = false; + + // Replace the chosen caps of dummy-surface w/ it's clone and copied values of orig FBO caps request. + // The dummy-surface has already been configured, hence value replace is OK + // and due to cloning, the native GLCapability portion is being preserved. + final MutableGraphicsConfiguration msConfig = (MutableGraphicsConfiguration) surface.getGraphicsConfiguration(); + final GLCapabilities fboCapsNative = (GLCapabilities) msConfig.getChosenCapabilities().cloneMutable(); + fboCapsNative.copyFrom(fboCaps); + msConfig.setChosenCapabilities(fboCapsNative); + this.parent = parent; this.texUnit = textureUnit; - final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); - this.width = initialWidth; - this.height = initialHeight; - this.samples = caps.getNumSamples(); - this.fbo = new FBObject(); + this.samples = fboCaps.getNumSamples(); + + // default .. // TODO: Add or remove TEXTURE (only) DoubleBufferMode support + // this.doubleBufferMode = ( samples > 0 || fboCaps.getDoubleBuffered() ) ? DoubleBufferMode.FBO : DoubleBufferMode.NONE ; + + this.swapBufferContext = null; } - @Override - protected void contextRealized(GLContext glc, boolean realized) { - final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); - final GL gl = glc.getGL(); - if(realized) { - fbo.reset(gl, width, height, samples); - samples = fbo.getNumSamples(); // update, maybe capped + private final void initialize(boolean realize, GL gl) { + if(realize) { + final int maxSamples = gl.getMaxRenderbufferSamples(); + samples = samples <= maxSamples ? samples : maxSamples; + + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); + final int fbosN; if(samples > 0) { - fbo.attachColorbuffer(gl, 0, caps.getAlphaBits()>0); + fbosN = 1; + } else if( caps.getDoubleBuffered() ) { + fbosN = bufferCount; } else { - fbo.attachTexture2D(gl, 0, caps.getAlphaBits()>0); + fbosN = 1; } - if( caps.getStencilBits() > 0 ) { - fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); - } else { - fbo.attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); + + fbos = new FBObject[fbosN]; + fboIBack = 0; // head + fboIFront = fbos.length - 1; // tail + + for(int i=0; i<fbosN; i++) { + fbos[i] = new FBObject(); + fbos[i].reset(gl, getWidth(), getHeight(), samples); + if(fbos[i].getNumSamples() != samples) { + throw new InternalError("Sample number mismatch: "+samples+", fbos["+i+"] "+fbos[i]); + } + if(samples > 0) { + fbos[i].attachColorbuffer(gl, 0, caps.getAlphaBits()>0); + } else { + fbos[i].attachTexture2D(gl, 0, caps.getAlphaBits()>0); + } + if( caps.getStencilBits() > 0 ) { + fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH_STENCIL, 24); + } else { + fbos[i].attachRenderbuffer(gl, Attachment.Type.DEPTH, 24); + } } - } else if(null != fbo) { - fbo.destroy(gl); - } - } - - @Override - protected void contextMadeCurrent(GLContext glc, boolean current) { - final GL gl = glc.getGL(); - if(current) { - fbo.bind(gl); + fbos[fboIFront].syncFramebuffer(gl); + fboBound = false; + final GLCapabilities fboCapsNative = (GLCapabilities) surface.getGraphicsConfiguration().getChosenCapabilities(); + fbos[0].formatToGLCapabilities(fboCapsNative); + fboCapsNative.setDoubleBuffered( fboCapsNative.getDoubleBuffered() || samples > 0 ); + + initialized = true; } else { - fbo.unbind(gl); - final TextureAttachment attachment = samples > 0 ? fbo.getSamplingSink() : (TextureAttachment) fbo.getColorbuffer(0) ; - if(null == attachment) { - throw new GLException("Null texture colorbuffer, samples "+samples+", "+fbo.toString()); - } - gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit); - fbo.use(gl, attachment ); - if( samples > 0) { - gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbo.getReadFramebuffer()); + initialized = false; + + for(int i=0; i<fbos.length; i++) { + fbos[i].destroy(gl); } + fbos=null; + fboBound = false; + pendingFBOReset = null; + } + if(DEBUG) { + System.err.println("GLFBODrawableImpl.initialize("+realize+"): "+this); + Thread.dumpStack(); } } - @Override - protected int getDefaultDrawFramebuffer() { return fbo.getWriteFramebuffer(); } - - @Override - protected int getDefaultReadFramebuffer() { return fbo.getReadFramebuffer(); } - - public FBObject getFBObject() { return fbo; } - - public void setSize(GL gl, int newWidth, int newHeight) throws GLException { - width = newWidth; - height = newHeight; - fbo.reset(gl, width, height, samples); - samples = fbo.getNumSamples(); // update, maybe capped + public final void setSwapBufferContext(SwapBufferContext sbc) { + swapBufferContext = sbc; + } + + private static final void reset(GL gl, FBObject fbo, int fboIdx, int width, int height, int samples) { + fbo.reset(gl, width, height, samples); // implicit glClear(..) + if(fbo.getNumSamples() != samples) { + throw new InternalError("Sample number mismatch: "+samples+", fbos["+fboIdx+"] "+fbo); + } } - public void setSamples(GL gl, int newSamples) throws GLException { - samples = newSamples; - fbo.reset(gl, width, height, samples); - samples = fbo.getNumSamples(); // update, maybe capped + private final void reset(GL gl, int newSamples) throws GLException { + if(!initialized) { + // NOP if not yet initializes + return; + } + + final GLContext curContext = GLContext.getCurrent(); + final GLContext ourContext = gl.getContext(); + final boolean ctxSwitch = null != curContext && curContext != ourContext; + if(DEBUG) { + System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): BEGIN - ctxSwitch "+ctxSwitch+", "+this); + Thread.dumpStack(); + } + Throwable tFBO = null; + Throwable tGL = null; + ourContext.makeCurrent(); + fboBound = false; // clear bound-flag immediatly, caused by contextMadeCurrent(..) - otherwise we would swap @ release + try { + final int maxSamples = gl.getMaxRenderbufferSamples(); + newSamples = newSamples <= maxSamples ? newSamples : maxSamples; + + if(0==samples && 0<newSamples || 0<samples && 0==newSamples) { + // MSAA on/off switch + if(DEBUG) { + System.err.println("GLFBODrawableImpl.reset(): samples [on/off] reconfig: "+samples+" -> "+newSamples); + } + initialize(false, gl); + samples = newSamples; + initialize(true, gl); + } else { + if(DEBUG) { + System.err.println("GLFBODrawableImpl.reset(): simple reconfig: "+samples+" -> "+newSamples); + } + final int nWidth = getWidth(); + final int nHeight = getHeight(); + samples = newSamples; + pendingFBOReset = ( 1 < fbos.length ) ? fbos[fboIFront] : null; // pending-front reset only w/ double buffering (or zero samples) + for(int i=0; i<fbos.length; i++) { + if(1 == fbos.length || fboIFront != i) { + reset(gl, fbos[i], i, nWidth, nHeight, samples); + } + } + final GLCapabilities fboCapsNative = (GLCapabilities) surface.getGraphicsConfiguration().getChosenCapabilities(); + fbos[0].formatToGLCapabilities(fboCapsNative); + } + } catch (Throwable t) { + tFBO = t; + } finally { + try { + ourContext.release(); + if(ctxSwitch) { + curContext.makeCurrent(); + } + } catch (Throwable t) { + tGL = t; + } + } + if(null != tFBO) { + throw new GLException("GLFBODrawableImpl.reset(..) FBObject.reset(..) exception", tFBO); + } + if(null != tGL) { + throw new GLException("GLFBODrawableImpl.reset(..) GLContext.release() exception", tGL); + } + if(DEBUG) { + System.err.println("GLFBODrawableImpl.reset(newSamples "+newSamples+"): END "+this); + } } + // + // GLDrawable + // @Override - public GLContext createContext(GLContext shareWith) { + public final GLContext createContext(GLContext shareWith) { final GLContext ctx = parent.createContext(shareWith); ctx.setGLDrawable(this, false); return ctx; } + // + // GLDrawableImpl + // + @Override - public GLDynamicLookupHelper getGLDynamicLookupHelper() { + public final GLDynamicLookupHelper getGLDynamicLookupHelper() { return parent.getGLDynamicLookupHelper(); } @Override - protected void swapBuffersImpl() { - } + protected final int getDefaultDrawFramebuffer() { return initialized ? fbos[fboIBack].getWriteFramebuffer() : 0; } + + @Override + protected final int getDefaultReadFramebuffer() { return initialized ? fbos[fboIFront].getReadFramebuffer() : 0; } @Override - protected void setRealizedImpl() { + protected final void setRealizedImpl() { parent.setRealized(realized); - if(realized) { - final MutableGraphicsConfiguration msConfig = (MutableGraphicsConfiguration) surface.getGraphicsConfiguration(); - final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) msConfig.getChosenCapabilities(); - final GLCapabilitiesImmutable chosenFBOCaps = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(chosenCaps, true /*FBO*/, false /*PBO*/); - msConfig.setChosenCapabilities(chosenFBOCaps); + } + + @Override + protected final void contextRealized(GLContext glc, boolean realized) { + initialize(realized, glc.getGL()); + } + + @Override + protected final void contextMadeCurrent(GLContext glc, boolean current) { + final GL gl = glc.getGL(); + if(current) { + fbos[fboIBack].bind(gl); + fboBound = true; + } else { + if(fboBound) { + swapFBOImpl(glc); + fboBound=false; + if(DEBUG) { + System.err.println("Post FBO swap(@release): done"); + } + } } } - + @Override - public int getWidth() { - return width; + protected void swapBuffersImpl(boolean doubleBuffered) { + final GLContext ctx = GLContext.getCurrent(); + if(null!=ctx && ctx.getGLDrawable()==this) { + if(fboBound) { + swapFBOImpl(ctx); + fboBound=false; + if(DEBUG) { + System.err.println("Post FBO swap(@swap): done"); + } + } + } + if(null != swapBufferContext) { + swapBufferContext.swapBuffers(doubleBuffered); + } + } + + private final void swapFBOImpl(GLContext glc) { + final GL gl = glc.getGL(); + fbos[fboIBack].markUnbound(); // fast path, use(gl,..) is called below + + // Safely reset the previous front FBO + if(null != pendingFBOReset) { + reset(gl, pendingFBOReset, fboIFront, getWidth(), getHeight(), samples); + pendingFBOReset = null; + } + + if(DEBUG) { + int _fboIFront = ( fboIFront + 1 ) % fbos.length; + if(_fboIFront != fboIBack) { throw new InternalError("XXX: "+_fboIFront+"!="+fboIBack); } + } + fboIFront = fboIBack; + fboIBack = ( fboIBack + 1 ) % fbos.length; + + final Colorbuffer colorbuffer = samples > 0 ? fbos[fboIFront].getSamplingSink() : fbos[fboIFront].getColorbuffer(0); + final TextureAttachment texAttachment; + if(colorbuffer instanceof TextureAttachment) { + texAttachment = (TextureAttachment) colorbuffer; + } else { + if(null == colorbuffer) { + throw new GLException("Front colorbuffer is null: samples "+samples+", "+this); + } else { + throw new GLException("Front colorbuffer is not a texture: "+colorbuffer.getClass().getName()+": samples "+samples+", "+colorbuffer+", "+this); + } + } + gl.glActiveTexture(GL.GL_TEXTURE0 + texUnit); + fbos[fboIFront].use(gl, texAttachment); + + /* Included in above use command: + gl.glBindFramebuffer(GL2GL3.GL_DRAW_FRAMEBUFFER, fbos[fboIBack].getDrawFramebuffer()); + gl.glBindFramebuffer(GL2GL3.GL_READ_FRAMEBUFFER, fbos[fboIFront].getReadFramebuffer()); + } */ + + if(DEBUG) { + System.err.println("Post FBO swap(X): fboI back "+fboIBack+", front "+fboIFront+", num "+fbos.length); + } } + // + // GLFBODrawable + // + + @Override + public final boolean isInitialized() { + return initialized; + } + @Override - public int getHeight() { - return height; + public final void resetSize(GL gl) throws GLException { + reset(gl, samples); } + + @Override + public final int getTextureUnit() { return texUnit; } + + @Override + public final void setTextureUnit(int u) { texUnit = u; } + + @Override + public final int getNumSamples() { return samples; } + + @Override + public void setNumSamples(GL gl, int newSamples) throws GLException { + if(samples != newSamples) { + reset(gl, newSamples); + } + } + + /** // TODO: Add or remove TEXTURE (only) DoubleBufferMode support + @Override + public final DoubleBufferMode getDoubleBufferMode() { + return doubleBufferMode; + } + + @Override + public final void setDoubleBufferMode(DoubleBufferMode mode) throws GLException { + if(initialized) { + throw new GLException("Not allowed past initialization: "+this); + } + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) surface.getGraphicsConfiguration().getChosenCapabilities(); + if(0 == samples && caps.getDoubleBuffered() && DoubleBufferMode.NONE != mode) { + doubleBufferMode = mode; + } + } */ + + @Override + public FBObject getFBObject(int bufferName) throws IllegalArgumentException { + if(!initialized) { + return null; + } + final FBObject res; + switch(bufferName) { + case GL.GL_FRONT: + if( samples > 0 ) { + res = fbos[0].getSamplingSinkFBO(); + } else { + res = fbos[fboIFront]; + } + break; + case GL.GL_BACK: + res = fbos[fboIBack]; + break; + default: + throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName)); + } + return res; + } + + @Override + public final TextureAttachment getTextureBuffer(int bufferName) throws IllegalArgumentException { + if(!initialized) { + return null; + } + final TextureAttachment res; + switch(bufferName) { + case GL.GL_FRONT: + if( samples > 0 ) { + res = fbos[0].getSamplingSink(); + } else { + res = (TextureAttachment) fbos[fboIFront].getColorbuffer(0); + } + break; + case GL.GL_BACK: + if( samples > 0 ) { + throw new IllegalArgumentException("Cannot access GL_BACK buffer of MSAA FBO: "+this); + } else { + res = (TextureAttachment) fbos[fboIBack].getColorbuffer(0); + } + break; + default: + throw new IllegalArgumentException(illegalBufferName+toHexString(bufferName)); + } + return res; + } + private static final String illegalBufferName = "Only GL_FRONT and GL_BACK buffer are allowed, passed "; + + @Override + public String toString() { + return getClass().getSimpleName()+"[Initialized "+initialized+", realized "+isRealized()+", texUnit "+texUnit+", samples "+samples+ + ",\n\tFactory "+getFactory()+ + ",\n\tHandle "+toHexString(getHandle())+ + ",\n\tCaps "+surface.getGraphicsConfiguration().getChosenCapabilities()+ + ",\n\tfboI back "+fboIBack+", front "+fboIFront+", num "+(initialized ? fbos.length : 0)+ + ",\n\tFBO front read "+getDefaultReadFramebuffer()+", "+getFBObject(GL.GL_FRONT)+ + ",\n\tFBO back write "+getDefaultDrawFramebuffer()+", "+getFBObject(GL.GL_BACK)+ + ",\n\tSurface "+getNativeSurface()+ + "]"; + } + + public static class ResizeableImpl extends GLFBODrawableImpl implements GLFBODrawable.Resizeable { + protected ResizeableImpl(GLDrawableFactoryImpl factory, GLDrawableImpl parent, ProxySurface surface, + GLCapabilitiesImmutable fboCaps, int textureUnit) { + super(factory, parent, surface, fboCaps, textureUnit); + } + + @Override + public final void setSize(GLContext context, int newWidth, int newHeight) throws NativeWindowException, GLException { + if(DEBUG) { + System.err.println("GLFBODrawableImpl.ResizeableImpl setSize: ("+Thread.currentThread().getName()+"): "+newWidth+"x"+newHeight+" - surfaceHandle 0x"+Long.toHexString(getNativeSurface().getSurfaceHandle())); + } + int lockRes = lockSurface(); + if (NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes) { + throw new NativeWindowException("Could not lock surface: "+this); + } + try { + // propagate new size + final ProxySurface ps = (ProxySurface) getNativeSurface(); + final UpstreamSurfaceHook ush = ps.getUpstreamSurfaceHook(); + if(ush instanceof UpstreamSurfaceHook.MutableSize) { + ((UpstreamSurfaceHook.MutableSize)ush).setSize(newWidth, newHeight); + } else { + throw new InternalError("GLFBODrawableImpl.ResizableImpl's ProxySurface doesn't hold a UpstreamSurfaceHookMutableSize but "+ush.getClass().getName()+", "+ps+", ush"); + } + if( null != context && context.isCreated() ) { + resetSize(context.getGL()); + } + } finally { + unlockSurface(); + } + } + } } diff --git a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java index 3f38f33bc..79f96b64a 100644 --- a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java +++ b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java @@ -28,17 +28,19 @@ package jogamp.opengl; -import java.util.List; - +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; + +import com.jogamp.common.os.Platform; public class GLGraphicsConfigurationUtil { public static final String NV_coverage_sample = "NV_coverage_sample"; public static final int WINDOW_BIT = 1 << 0; public static final int BITMAP_BIT = 1 << 1; public static final int PBUFFER_BIT = 1 << 2; - public static final int FBO_BIT = 1 << 3; + public static final int FBO_BIT = 1 << 3; // generic bit must be mapped to native one at impl. level public static final int ALL_BITS = WINDOW_BIT | BITMAP_BIT | PBUFFER_BIT | FBO_BIT ; public static final StringBuilder winAttributeBits2String(StringBuilder sb, int winattrbits) { @@ -74,90 +76,117 @@ public class GLGraphicsConfigurationUtil { } /** - * @param isFBO TODO - * @return bitmask representing the input boolean in exclusive or logic, ie only one bit will be set + public static final int getWinAttributeBits(boolean isOnscreen, boolean isFBO, boolean isPBuffer, boolean isBitmap) { + int winattrbits = 0; + if(isOnscreen) { + winattrbits |= WINDOW_BIT; + } + if(isFBO) { + winattrbits |= FBO_BIT; + } + if(isPBuffer ){ + winattrbits |= PBUFFER_BIT; + } + if(isBitmap) { + winattrbits |= BITMAP_BIT; + } + return winattrbits; + } + public static final int getWinAttributeBits(GLCapabilitiesImmutable caps) { + return getWinAttributeBits(caps.isOnscreen(), caps.isFBO(), caps.isPBuffer(), caps.isBitmap()); + } */ + + /** + * @return bitmask representing the input boolean in exclusive or logic, ie only one bit will be set. */ - public static final int getWinAttributeBits(boolean isOnscreen, boolean isPBuffer, boolean isFBO) { + public static final int getExclusiveWinAttributeBits(boolean isOnscreen, boolean isFBO, boolean isPBuffer, boolean isBitmap) { int winattrbits = 0; if(isOnscreen) { winattrbits |= WINDOW_BIT; - } else { - if(isFBO) { - winattrbits |= FBO_BIT; - } - if (!isPBuffer) { - winattrbits |= BITMAP_BIT; - } else { - winattrbits |= PBUFFER_BIT; - } + } else if(isFBO) { + winattrbits |= FBO_BIT; + } else if(isPBuffer ){ + winattrbits |= PBUFFER_BIT; + } else if(isBitmap) { + winattrbits |= BITMAP_BIT; + } + if(0 == winattrbits) { + throw new InternalError("Empty bitmask"); } return winattrbits; } /** - * @see #getWinAttributeBits(boolean, boolean, boolean) + * @see #getExclusiveWinAttributeBits(boolean, boolean, boolean, boolean) */ - public static final int getWinAttributeBits(GLCapabilitiesImmutable caps) { - return getWinAttributeBits(caps.isOnscreen(), caps.isPBuffer(), false); + public static final int getExclusiveWinAttributeBits(GLCapabilitiesImmutable caps) { + return getExclusiveWinAttributeBits(caps.isOnscreen(), caps.isFBO(), caps.isPBuffer(), caps.isBitmap()); } - public static final boolean addGLCapabilitiesPermutations(List<GLCapabilitiesImmutable> capsBucket, GLCapabilitiesImmutable temp, int winattrbits) { - int preSize = capsBucket.size(); - if( 0 != ( WINDOW_BIT & winattrbits ) ) { - GLCapabilities cpy = (GLCapabilities) temp.cloneMutable(); - cpy.setOnscreen(true); - cpy.setPBuffer(false); - cpy.setFBO(false); - capsBucket.add(cpy); - } - if( 0 != ( PBUFFER_BIT & winattrbits ) || 0 != ( FBO_BIT & winattrbits ) ) { - GLCapabilities cpy = (GLCapabilities) temp.cloneMutable(); - cpy.setFBO(0 != ( FBO_BIT & winattrbits )); - cpy.setPBuffer(0 != ( PBUFFER_BIT & winattrbits )); - capsBucket.add(cpy); - } - if( 0 != ( BITMAP_BIT & winattrbits ) ) { - GLCapabilities cpy = (GLCapabilities) temp.cloneMutable(); - cpy.setOnscreen(false); - cpy.setPBuffer(false); - cpy.setFBO(false); - capsBucket.add(cpy); + public static final GLCapabilities fixWinAttribBitsAndHwAccel(AbstractGraphicsDevice device, int winattrbits, GLCapabilities caps) { + caps.setBitmap ( 0 != ( BITMAP_BIT & winattrbits ) ); + caps.setPBuffer ( 0 != ( PBUFFER_BIT & winattrbits ) ); + caps.setFBO ( 0 != ( FBO_BIT & winattrbits ) ); + // we reflect availability semantics, hence setting onscreen at last (maybe overwritten above)! + caps.setOnscreen( 0 != ( WINDOW_BIT & winattrbits ) ); + + final int accel = GLContext.isHardwareRasterizer( device, caps.getGLProfile() ); + if(0 == accel && caps.getHardwareAccelerated() ) { + caps.setHardwareAccelerated(false); } - return capsBucket.size() > preSize; - } + return caps; + } + public static GLCapabilitiesImmutable fixGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean fboAvailable, boolean pbufferAvailable) { if( !capsRequested.isOnscreen() ) { return fixOffscreenGLCapabilities(capsRequested, fboAvailable, pbufferAvailable); - } - return fixOnscreenGLCapabilities(capsRequested); + } /* we maintain the offscreen mode flags in onscreen mode - else { + return fixOnscreenGLCapabilities(capsRequested); + } */ + return capsRequested; } public static GLCapabilitiesImmutable fixOnscreenGLCapabilities(GLCapabilitiesImmutable capsRequested) { - if( !capsRequested.isOnscreen() ) { + if( !capsRequested.isOnscreen() || capsRequested.isFBO() || capsRequested.isPBuffer() || capsRequested.isBitmap() ) { // fix caps .. - GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); + final GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); + caps2.setBitmap (false); + caps2.setPBuffer (false); + caps2.setFBO (false); caps2.setOnscreen(true); return caps2; } return capsRequested; } - - public static GLCapabilitiesImmutable fixOffscreenGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean fboAvailable, boolean pbufferAvailable) - { - if( capsRequested.getDoubleBuffered() || - capsRequested.isOnscreen() || - ( fboAvailable != capsRequested.isFBO() ) || - ( pbufferAvailable != capsRequested.isPBuffer() ) ) + + public static boolean isGLCapabilitiesOffscreenAutoSelection(GLCapabilitiesImmutable capsRequested) { + return !capsRequested.isOnscreen() && + !capsRequested.isFBO() && !capsRequested.isPBuffer() && !capsRequested.isBitmap() ; + } + + public static GLCapabilitiesImmutable fixOffscreenGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean fboAvailable, boolean pbufferAvailable) { + final boolean auto = !capsRequested.isFBO() && !capsRequested.isPBuffer() && !capsRequested.isBitmap() ; + + final boolean requestedPBuffer = capsRequested.isPBuffer() || Platform.getOSType() == Platform.OSType.MACOS ; // no native bitmap for OSX + + final boolean useFBO = fboAvailable && ( auto || capsRequested.isFBO() ) ; + final boolean usePbuffer = !useFBO && pbufferAvailable && ( auto || requestedPBuffer ) ; + final boolean useBitmap = !useFBO && !usePbuffer && ( auto || capsRequested.isBitmap() ) ; + + if( capsRequested.isOnscreen() || + useFBO != capsRequested.isFBO() || + usePbuffer != capsRequested.isPBuffer() || + useBitmap != capsRequested.isBitmap() ) { // fix caps .. - GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); - caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN + final GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); caps2.setOnscreen(false); - caps2.setFBO( fboAvailable ); - caps2.setPBuffer( pbufferAvailable ); + caps2.setFBO( useFBO ); + caps2.setPBuffer( usePbuffer ); + caps2.setBitmap( useBitmap ); return caps2; } return capsRequested; @@ -165,31 +194,40 @@ public class GLGraphicsConfigurationUtil { public static GLCapabilitiesImmutable fixGLPBufferGLCapabilities(GLCapabilitiesImmutable capsRequested) { - if( capsRequested.getDoubleBuffered() || capsRequested.isOnscreen() || !capsRequested.isPBuffer() || capsRequested.isFBO() ) { + if( capsRequested.isOnscreen() || + !capsRequested.isPBuffer() || + capsRequested.isFBO() ) + { // fix caps .. - GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); - caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN - we don't need to be single buffered .. + final GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); caps2.setOnscreen(false); - caps2.setPBuffer(true); caps2.setFBO(false); + caps2.setPBuffer(true); + caps2.setBitmap(false); return caps2; } return capsRequested; } /** Fix opaque setting while preserve alpha bits */ - public static GLCapabilitiesImmutable fixOpaqueGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean isOpaque) + public static GLCapabilities fixOpaqueGLCapabilities(GLCapabilities capsRequested, boolean isOpaque) { - GLCapabilities caps2 = null; - if( capsRequested.isBackgroundOpaque() != isOpaque) { final int alphaBits = capsRequested.getAlphaBits(); - caps2 = (GLCapabilities) capsRequested.cloneMutable(); - caps2.setBackgroundOpaque(isOpaque); - caps2.setAlphaBits(alphaBits); - return caps2; + capsRequested.setBackgroundOpaque(isOpaque); + capsRequested.setAlphaBits(alphaBits); } return capsRequested; } + /** Fix double buffered setting */ + public static GLCapabilitiesImmutable fixDoubleBufferedGLCapabilities(GLCapabilitiesImmutable capsRequested, boolean doubleBuffered) + { + if( capsRequested.getDoubleBuffered() != doubleBuffered) { + final GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); + caps2.setDoubleBuffered(doubleBuffered); + return caps2; + } + return capsRequested; + } } diff --git a/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java new file mode 100644 index 000000000..7701f209f --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/GLOffscreenAutoDrawableImpl.java @@ -0,0 +1,123 @@ +/** + * Copyright 2012 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 jogamp.opengl; + +import javax.media.nativewindow.NativeWindowException; +import javax.media.opengl.GL; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLOffscreenAutoDrawable; + +import com.jogamp.common.util.locks.RecursiveLock; +import com.jogamp.opengl.FBObject; +import com.jogamp.opengl.GLAutoDrawableDelegate; + +import jogamp.opengl.GLFBODrawableImpl; + +public class GLOffscreenAutoDrawableImpl extends GLAutoDrawableDelegate implements GLOffscreenAutoDrawable { + + /** + * @param drawable a valid and already realized {@link GLDrawable} + * @param context a valid {@link GLContext}, may not be made current (created) yet. + * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}. + * @param lock optional upstream lock, may be null + */ + public GLOffscreenAutoDrawableImpl(GLDrawable drawable, GLContext context, Object upstreamWidget, RecursiveLock lock) { + super(drawable, context, upstreamWidget, true, lock); + } + + @Override + public void setSize(int newWidth, int newHeight) throws NativeWindowException, GLException { + this.defaultWindowResizedOp(newWidth, newHeight); + } + + public static class FBOImpl extends GLOffscreenAutoDrawableImpl implements GLOffscreenAutoDrawable.FBO { + /** + * @param drawable a valid and already realized {@link GLDrawable} + * @param context a valid {@link GLContext}, may not be made current (created) yet. + * @param upstreamWidget optional UI element holding this instance, see {@link #getUpstreamWidget()}. + * @param lock optional upstream lock, may be null + */ + public FBOImpl(GLFBODrawableImpl drawable, GLContext context, Object upstreamWidget, RecursiveLock lock) { + super(drawable, context, upstreamWidget, lock); + } + + @Override + public boolean isInitialized() { + return ((GLFBODrawableImpl)drawable).isInitialized(); + } + + @Override + public final int getTextureUnit() { + return ((GLFBODrawableImpl)drawable).getTextureUnit(); + } + + @Override + public final void setTextureUnit(int unit) { + ((GLFBODrawableImpl)drawable).setTextureUnit(unit); + } + + @Override + public final int getNumSamples() { + return ((GLFBODrawableImpl)drawable).getNumSamples(); + } + + @Override + public final void setNumSamples(GL gl, int newSamples) throws GLException { + ((GLFBODrawableImpl)drawable).setNumSamples(gl, newSamples); + windowRepaintOp(); + } + + /** // TODO: Add or remove TEXTURE (only) DoubleBufferMode support + @Override + public DoubleBufferMode getDoubleBufferMode() { + return ((GLFBODrawableImpl)drawable).getDoubleBufferMode(); + } + + @Override + public void setDoubleBufferMode(DoubleBufferMode mode) throws GLException { + ((GLFBODrawableImpl)drawable).setDoubleBufferMode(mode); + } */ + + @Override + public final FBObject getFBObject(int bufferName) { + return ((GLFBODrawableImpl)drawable).getFBObject(bufferName); + } + + public final FBObject.TextureAttachment getTextureBuffer(int bufferName) { + return ((GLFBODrawableImpl)drawable).getTextureBuffer(bufferName); + } + + @Override + public void resetSize(GL gl) throws GLException { + ((GLFBODrawableImpl)drawable).resetSize(gl); + } + } +} diff --git a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java index 32f4cb696..b438131bc 100644 --- a/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLPbufferImpl.java @@ -40,9 +40,6 @@ package jogamp.opengl; -import javax.media.opengl.GLCapabilitiesImmutable; -import javax.media.opengl.GLContext; -import javax.media.opengl.GLDrawable; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; @@ -50,36 +47,18 @@ import javax.media.opengl.GLPbuffer; import com.jogamp.common.util.locks.LockFactory; import com.jogamp.common.util.locks.RecursiveLock; -/** Platform-independent class exposing pbuffer functionality to - applications. This class is not exposed in the public API as it - would probably add no value; however it implements the GLDrawable - interface so can be interacted with via its display() method. */ - +@SuppressWarnings("deprecation") public class GLPbufferImpl extends GLAutoDrawableBase implements GLPbuffer { private int floatMode; - public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContext sharedContext, boolean ownDevice) { - super(pbufferDrawable, null, ownDevice); // drawable := pbufferDrawable - - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) - drawable.getNativeSurface().getGraphicsConfiguration().getChosenCapabilities(); - if(caps.isOnscreen()) { - if(caps.isPBuffer()) { - throw new IllegalArgumentException("Error: Given drawable is Onscreen and Pbuffer: "+pbufferDrawable); - } - throw new IllegalArgumentException("Error: Given drawable is Onscreen: "+pbufferDrawable); - } else { - if(!caps.isPBuffer()) { - throw new IllegalArgumentException("Error: Given drawable is not Pbuffer: "+pbufferDrawable); - } - } - context = (GLContextImpl) drawable.createContext(sharedContext); + public GLPbufferImpl(GLDrawableImpl pbufferDrawable, GLContextImpl pbufferContext) { + super(pbufferDrawable, pbufferContext, true); // drawable := pbufferDrawable, context := pbufferContext } // // pbuffer specifics - // - + // + @Override public void bindTexture() { // Doesn't make much sense to try to do this on the event dispatch diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java index 03d0d650f..06953a8e1 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLContext.java @@ -282,12 +282,6 @@ public abstract class EGLContext extends GLContextImpl { return EGL.eglSwapInterval(drawable.getNativeSurface().getDisplayHandle(), interval); } - @Override - public abstract void bindPbufferToTexture(); - - @Override - public abstract void releasePbufferFromTexture(); - // // Accessible .. // diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java index 18d2f830d..ce2e824f5 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDisplayUtil.java @@ -29,6 +29,7 @@ package jogamp.opengl.egl; import java.nio.IntBuffer; +import java.util.Iterator; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; @@ -51,7 +52,7 @@ import com.jogamp.nativewindow.egl.EGLGraphicsDevice; * </p> */ public class EGLDisplayUtil { - protected static final boolean DEBUG = Debug.debug("EGL"); + protected static final boolean DEBUG = Debug.debug("EGLDisplayUtil"); static LongIntHashMap eglDisplayCounter; @@ -60,6 +61,32 @@ public class EGLDisplayUtil { eglDisplayCounter.setKeyNotFoundValue(0); } + /** + * @return number of unclosed EGL Displays.<br> + */ + public static int shutdown(boolean verbose) { + if(DEBUG || verbose || eglDisplayCounter.size() > 0 ) { + System.err.println("EGLDisplayUtil.EGLDisplays: Shutdown (open: "+eglDisplayCounter.size()+")"); + if(DEBUG) { + Thread.dumpStack(); + } + if( eglDisplayCounter.size() > 0) { + EGLDisplayUtil.dumpOpenDisplayConnections(); + } + } + + return eglDisplayCounter.size(); + } + + public static void dumpOpenDisplayConnections() { + System.err.println("EGLDisplayUtil: Open EGL Display Connections: "+eglDisplayCounter.size()); + int i=0; + for(Iterator<LongIntHashMap.Entry> iter = eglDisplayCounter.iterator(); iter.hasNext(); i++) { + final LongIntHashMap.Entry e = iter.next(); + System.err.println("EGLDisplayUtil: Open["+i+"]: 0x"+Long.toHexString(e.key)+": refCnt "+e.value); + } + } + public static long eglGetDisplay(long nativeDisplay_id) { final long eglDisplay = EGL.eglGetDisplay(nativeDisplay_id); if(DEBUG) { @@ -89,6 +116,7 @@ public class EGLDisplayUtil { eglDisplayCounter.put(eglDisplay, refCnt); if(DEBUG) { System.err.println("EGLDisplayUtil.eglInitialize1("+EGLContext.toHexString(eglDisplay)+" ...): #"+refCnt+" = "+res); + // Thread.dumpStack(); } return res; } @@ -117,6 +145,7 @@ public class EGLDisplayUtil { } if(DEBUG) { System.err.println("EGLDisplayUtil.eglInitialize2("+EGLContext.toHexString(eglDisplay)+" ...): #"+refCnt+" = "+res); + // Thread.dumpStack(); } return res; } @@ -185,12 +214,13 @@ public class EGLDisplayUtil { final int refCnt = eglDisplayCounter.get(eglDisplay) - 1; // 1 - 1 = 0 -> final terminate if(0==refCnt) { // no terminate if still in use or already terminated res = EGL.eglTerminate(eglDisplay); + eglDisplayCounter.remove(eglDisplay); } else { + if(0 < refCnt) { // no negative refCount + eglDisplayCounter.put(eglDisplay, refCnt); + } res = true; } - if(0<=refCnt) { // no negative refCount - eglDisplayCounter.put(eglDisplay, refCnt); - } if(DEBUG) { System.err.println("EGLDisplayUtil.eglTerminate("+EGLContext.toHexString(eglDisplay)+" ...): #"+refCnt+" = "+res); // Thread.dumpStack(); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index 0dba4bb09..167eebf3a 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -36,7 +36,8 @@ package jogamp.opengl.egl; -import javax.media.nativewindow.MutableSurface; +import java.nio.IntBuffer; + import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.ProxySurface; @@ -46,10 +47,10 @@ import javax.media.opengl.GLException; import jogamp.opengl.GLDrawableImpl; import jogamp.opengl.GLDynamicLookupHelper; +import com.jogamp.common.nio.Buffers; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; public abstract class EGLDrawable extends GLDrawableImpl { - private boolean ownEGLSurface = false; // for destruction protected EGLDrawable(EGLDrawableFactory factory, NativeSurface component) throws GLException { super(factory, component, false); @@ -58,21 +59,14 @@ public abstract class EGLDrawable extends GLDrawableImpl { @Override public abstract GLContext createContext(GLContext shareWith); - protected abstract long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle); + protected abstract long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle); - private final void recreateSurface() { - final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) surface.getGraphicsConfiguration(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglConfig.getScreen().getDevice(); - if(DEBUG) { - System.err.println(getThreadName() + ": createSurface using "+eglConfig); - } - if( EGL.EGL_NO_SURFACE != surface.getSurfaceHandle() ) { - EGL.eglDestroySurface(eglDevice.getHandle(), surface.getSurfaceHandle()); - } + private final long createEGLSurface() { + final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) eglws.getGraphicsConfiguration(); + final NativeSurface upstreamSurface = eglws.getUpstreamSurface(); - final EGLUpstreamSurfaceHook upstreamHook = (EGLUpstreamSurfaceHook) ((ProxySurface)surface).getUpstreamSurfaceHook(); - final NativeSurface upstreamSurface = upstreamHook.getUpstreamSurface(); - long eglSurface = createSurface(eglConfig, upstreamSurface.getSurfaceHandle()); + long eglSurface = createSurface(eglConfig, eglws.getWidth(), eglws.getHeight(), upstreamSurface.getSurfaceHandle()); int eglError0; if (EGL.EGL_NO_SURFACE == eglSurface) { @@ -86,7 +80,7 @@ public abstract class EGLDrawable extends GLDrawableImpl { if(DEBUG) { System.err.println(getThreadName() + ": Info: Creation of window surface w/ surface handle failed: "+eglConfig+", error "+toHexString(eglError0)+", retry w/ windowHandle"); } - eglSurface = createSurface(eglConfig, nw.getWindowHandle()); + eglSurface = createSurface(eglConfig, eglws.getWidth(), eglws.getHeight(), nw.getWindowHandle()); if (EGL.EGL_NO_SURFACE == eglSurface) { eglError0 = EGL.eglGetError(); } @@ -99,34 +93,53 @@ public abstract class EGLDrawable extends GLDrawableImpl { if (EGL.EGL_NO_SURFACE == eglSurface) { throw new GLException("Creation of window surface failed: "+eglConfig+", "+surface+", error "+toHexString(eglError0)); } - if(DEBUG) { - System.err.println(getThreadName() + ": setSurface using component: handle "+toHexString(surface.getSurfaceHandle())+" -> "+toHexString(eglSurface)); + System.err.println(getThreadName() + ": createEGLSurface handle "+toHexString(eglSurface)); } - - ((MutableSurface)surface).setSurfaceHandle(eglSurface); + return eglSurface; } @Override protected final void updateHandle() { - if(ownEGLSurface) { - recreateSurface(); + final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + if(DEBUG) { + System.err.println(getThreadName() + ": updateHandle of "+eglws); + } + if( eglws.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + if( EGL.EGL_NO_SURFACE != eglws.getSurfaceHandle() ) { + throw new InternalError("Set surface but claimed to be invalid: "+eglws); + } + eglws.setSurfaceHandle( createEGLSurface() ); + } else if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) { + throw new InternalError("Nil surface but claimed to be valid: "+eglws); + } + } + + protected void destroyHandle() { + final EGLWrappedSurface eglws = (EGLWrappedSurface) surface; + if(DEBUG) { + System.err.println(getThreadName() + ": destroyHandle of "+eglws); + } + if( EGL.EGL_NO_SURFACE == eglws.getSurfaceHandle() ) { + throw new InternalError("Nil surface but claimed to be valid: "+eglws); + } + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglws.getGraphicsConfiguration().getScreen().getDevice(); + if( eglws.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + EGL.eglDestroySurface(eglDevice.getHandle(), eglws.getSurfaceHandle()); + eglws.setSurfaceHandle(EGL.EGL_NO_SURFACE); } } - protected static boolean isValidEGLSurface(EGLGraphicsDevice eglDevice, NativeSurface surface) { - final long eglDisplayHandle = eglDevice.getHandle(); - if (EGL.EGL_NO_DISPLAY == eglDisplayHandle) { - throw new GLException("Invalid EGL display in EGLGraphicsDevice "+eglDevice); + protected static boolean isValidEGLSurface(long eglDisplayHandle, long surfaceHandle) { + if( 0 == surfaceHandle ) { + return false; } - boolean eglSurfaceValid = 0 != surface.getSurfaceHandle(); - if(eglSurfaceValid) { - int[] tmp = new int[1]; - eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, surface.getSurfaceHandle(), EGL.EGL_CONFIG_ID, tmp, 0); - if(!eglSurfaceValid) { - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.isValidEGLSurface eglQuerySuface failed: "+toHexString(EGL.eglGetError())+", "+surface); - } + final IntBuffer val = Buffers.newDirectIntBuffer(1); + final boolean eglSurfaceValid = EGL.eglQuerySurface(eglDisplayHandle, surfaceHandle, EGL.EGL_CONFIG_ID, val); + if( !eglSurfaceValid ) { + final int eglErr = EGL.eglGetError(); + if(DEBUG) { + System.err.println(getThreadName() + ": EGLDrawable.isValidEGLSurface eglQuerySuface failed: error "+toHexString(eglErr)+", "+toHexString(surfaceHandle)); } } return eglSurfaceValid; @@ -134,55 +147,19 @@ public abstract class EGLDrawable extends GLDrawableImpl { @Override protected final void setRealizedImpl() { - final EGLGraphicsConfiguration eglConfig = (EGLGraphicsConfiguration) surface.getGraphicsConfiguration(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) eglConfig.getScreen().getDevice(); - if (realized) { - final boolean eglSurfaceValid = isValidEGLSurface(eglDevice, surface); - if(eglSurfaceValid) { - // surface holds valid EGLSurface - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.setRealizedImpl re-using component's EGLSurface: handle "+toHexString(surface.getSurfaceHandle())); - } - ownEGLSurface=false; - } else { - // EGLSurface is ours - subsequent updateHandle() will issue recreateSurface(); - // However .. let's validate the surface object first - if( ! (surface instanceof ProxySurface) ) { - throw new InternalError("surface not ProxySurface: "+surface.getClass().getName()+", "+surface); - } - final ProxySurface.UpstreamSurfaceHook upstreamHook = ((ProxySurface)surface).getUpstreamSurfaceHook(); - if( null == upstreamHook ) { - throw new InternalError("null upstreamHook of: "+surface); - } - if( ! (upstreamHook instanceof EGLUpstreamSurfaceHook) ) { - throw new InternalError("upstreamHook not EGLUpstreamSurfaceHook: Surface: "+surface.getClass().getName()+", "+surface+"; UpstreamHook: "+upstreamHook.getClass().getName()+", "+upstreamHook); - } - if( null == ((EGLUpstreamSurfaceHook)upstreamHook).getUpstreamSurface() ) { - throw new InternalError("null upstream surface"); - } - ownEGLSurface=true; - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.setRealizedImpl owning EGLSurface"); - } - } - } else if (ownEGLSurface && surface.getSurfaceHandle() != EGL.EGL_NO_SURFACE) { - if(DEBUG) { - System.err.println(getThreadName() + ": EGLDrawable.setRealized(false): ownSurface "+ownEGLSurface+", "+eglDevice+", eglSurface: "+toHexString(surface.getSurfaceHandle())); - } - // Destroy the window surface - if (!EGL.eglDestroySurface(eglDevice.getHandle(), surface.getSurfaceHandle())) { - throw new GLException("Error destroying window surface (eglDestroySurface)"); - } - ((MutableSurface)surface).setSurfaceHandle(EGL.EGL_NO_SURFACE); + if(DEBUG) { + System.err.println(getThreadName() + ": EGLDrawable.setRealized("+realized+"): NOP - "+surface); } } @Override - protected final void swapBuffersImpl() { - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); - // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() - if(!EGL.eglSwapBuffers(eglDevice.getHandle(), surface.getSurfaceHandle())) { - throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); + protected final void swapBuffersImpl(boolean doubleBuffered) { + if(doubleBuffered) { + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!EGL.eglSwapBuffers(eglDevice.getHandle(), surface.getSurfaceHandle())) { + throw new GLException("Error swapping buffers, eglError "+toHexString(EGL.eglGetError())+", "+this); + } } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index a9e339bea..e98d69140 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -52,8 +52,7 @@ import javax.media.nativewindow.MutableSurface; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; -import javax.media.nativewindow.VisualIDHolder.VIDType; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; @@ -64,8 +63,8 @@ import javax.media.opengl.GLDrawable; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import javax.media.opengl.GLProfile.ShutdownType; +import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.Debug; import jogamp.opengl.GLDrawableFactoryImpl; import jogamp.opengl.GLDrawableImpl; @@ -77,10 +76,11 @@ import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.nativewindow.WrappedSurface; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; public class EGLDrawableFactory extends GLDrawableFactoryImpl { + protected static final boolean DEBUG = GLDrawableFactoryImpl.DEBUG; + /* package */ static final boolean QUERY_EGL_ES = !Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.DontQuery", true); /* package */ static final boolean QUERY_EGL_ES_NATIVE_TK = Debug.isPropertyDefined("jogl.debug.EGLDrawableFactory.QueryNativeTK", true); @@ -113,7 +113,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } catch (JogampRuntimeException jre) { /* n/a .. */ } } - defaultDevice = new EGLGraphicsDevice(AbstractGraphicsDevice.DEFAULT_CONNECTION, AbstractGraphicsDevice.DEFAULT_UNIT); + defaultDevice = new EGLGraphicsDevice(); // FIXME: Probably need to move EGL from a static model // to a dynamic one, where there can be 2 instances @@ -201,13 +201,13 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { @Override - protected final void destroy(ShutdownType shutdownType) { + protected final void destroy() { if(null != sharedMap) { Collection<SharedResource> srl = sharedMap.values(); for(Iterator<SharedResource> sri = srl.iterator(); sri.hasNext(); ) { SharedResource sr = sri.next(); if(DEBUG) { - System.err.println("EGLDrawableFactory.destroy("+shutdownType+"): "+sr.device.toString()); + System.err.println("EGLDrawableFactory.destroy(): "+sr.device.toString()); } sr.device.close(); } @@ -220,17 +220,16 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { /** * Pulling away the native library may cause havoc .. */ - if(ShutdownType.COMPLETE == shutdownType) { - if(null != eglES1DynamicLookupHelper) { - // eglES1DynamicLookupHelper.destroy(); - eglES1DynamicLookupHelper = null; - } - if(null != eglES2DynamicLookupHelper) { - // eglES2DynamicLookupHelper.destroy(); - eglES2DynamicLookupHelper = null; - } + if(null != eglES1DynamicLookupHelper) { + // eglES1DynamicLookupHelper.destroy(); + eglES1DynamicLookupHelper = null; + } + if(null != eglES2DynamicLookupHelper) { + // eglES2DynamicLookupHelper.destroy(); + eglES2DynamicLookupHelper = null; } EGLGraphicsConfigurationFactory.unregisterFactory(); + EGLDisplayUtil.shutdown(DEBUG); } private HashMap<String /*connection*/, SharedResource> sharedMap = null; @@ -290,9 +289,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if(0 < numConfigs.get(0)) { final PointerBuffer configs = PointerBuffer.allocateDirect(numConfigs.get(0)); final IntBuffer attrs = Buffers.newDirectIntBuffer(EGLGraphicsConfiguration.GLCapabilities2AttribList(caps)); - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(true, true, true); + final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(caps); if( EGL.eglChooseConfig(eglDisplay.getHandle(), attrs, configs, configs.capacity(), numConfigs) && numConfigs.get(0) > 0) { - return EGLGraphicsConfigurationFactory.eglConfigs2GLCaps(caps.getGLProfile(), eglDisplay.getHandle(), configs, numConfigs.get(0), winattrmask, false /* forceTransparentFlag */); + return EGLGraphicsConfigurationFactory.eglConfigs2GLCaps(eglDisplay, caps.getGLProfile(), configs, numConfigs.get(0), winattrmask, false /* forceTransparentFlag */); } } return new ArrayList<GLCapabilitiesImmutable>(0); @@ -312,6 +311,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { try { final GLCapabilities reqCapsAny = new GLCapabilities(glp); reqCapsAny.setRedBits(5); reqCapsAny.setGreenBits(5); reqCapsAny.setBlueBits(5); reqCapsAny.setAlphaBits(0); + reqCapsAny.setDoubleBuffered(false); final GLCapabilitiesImmutable reqCapsPBuffer = GLGraphicsConfigurationUtil.fixGLPBufferGLCapabilities(reqCapsAny); final List<GLCapabilitiesImmutable> availablePBufferCapsL = getAvailableEGLConfigs(sharedEGLDevice, reqCapsPBuffer); hasPBuffer[0] = availablePBufferCapsL.size() > 0; @@ -326,18 +326,20 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { } else { final List<GLCapabilitiesImmutable> capsAnyL = getAvailableEGLConfigs(eglDevice, reqCapsAny); if(capsAnyL.size() > 0) { - final GLCapabilitiesImmutable caps = capsAnyL.get(0); - EGLContext.mapStaticGLESVersion(eglDevice, caps); + final GLCapabilitiesImmutable chosenCaps = capsAnyL.get(0); + EGLContext.mapStaticGLESVersion(eglDevice, chosenCaps); if(eglDevice != adevice) { - EGLContext.mapStaticGLESVersion(adevice, caps); + EGLContext.mapStaticGLESVersion(adevice, chosenCaps); } + final EGLGraphicsDevice adeviceEGLDevice = new EGLGraphicsDevice(adevice.getHandle(), EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), null); + EGLContext.mapStaticGLESVersion(adeviceEGLDevice, chosenCaps); success = true; } if(DEBUG) { System.err.println("EGLDrawableFactory.isEGLContextAvailable() no pbuffer config available, detected !pbuffer config: "+success); EGLGraphicsConfigurationFactory.printCaps("!PBufferCaps", capsAnyL, System.err); } - } + } } else { surface = desktopFactory.createDummySurface(adevice, reqCapsAny, null, 64, 64); // X11, WGL, .. dummy window upstreamSurface = ( surface instanceof ProxySurface ) ? (ProxySurface)surface : null ; @@ -363,6 +365,8 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if(eglDevice != adevice) { context.mapCurrentAvailableGLVersion(adevice); } + final EGLGraphicsDevice adeviceEGLDevice = new EGLGraphicsDevice(adevice.getHandle(), EGL.EGL_NO_DISPLAY, adevice.getConnection(), adevice.getUnitID(), null); + context.mapCurrentAvailableGLVersion(adeviceEGLDevice); success = true; } else { // Oops .. something is wrong @@ -540,70 +544,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { if (target == null) { throw new IllegalArgumentException("Null target"); } - return new EGLOnscreenDrawable(this, getEGLSurface(target)); + return new EGLOnscreenDrawable(this, EGLWrappedSurface.get(target)); } - protected static NativeSurface getEGLSurface(NativeSurface surface) { - AbstractGraphicsConfiguration aConfig = surface.getGraphicsConfiguration(); - AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); - if( aDevice instanceof EGLGraphicsDevice && aConfig instanceof EGLGraphicsConfiguration ) { - if(surface instanceof WrappedSurface) { - // already wrapped surface - no wrapped recursion - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - already wrapped surface - use as-is: "+surface); - } - return surface; - } - if(EGLDrawable.isValidEGLSurface((EGLGraphicsDevice)aDevice, surface)) { - // already in native EGL format - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - already valid EGL surface - use as-is: "+surface); - } - return surface; - } - } - // create EGL instance out of platform native types - final EGLGraphicsDevice eglDevice; - if( aDevice instanceof EGLGraphicsDevice ) { - eglDevice = (EGLGraphicsDevice) aDevice; - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - Reusing eglDevice: "+eglDevice); - } - if(0 == eglDevice.getHandle()) { - eglDevice.open(); - } - } else { - eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(surface); - } - final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex()); - final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities(); - final EGLGraphicsConfiguration eglConfig; - if( aConfig instanceof EGLGraphicsConfiguration ) { - // Config is already in EGL type - reuse .. - final EGLGLCapabilities capsChosen = (EGLGLCapabilities) aConfig.getChosenCapabilities(); - if( 0 == capsChosen.getEGLConfig() ) { - // 'refresh' the native EGLConfig handle - capsChosen.setEGLConfig(EGLGraphicsConfiguration.EGLConfigId2EGLConfig(eglDevice.getHandle(), capsChosen.getEGLConfigID())); - if( 0 == capsChosen.getEGLConfig() ) { - throw new GLException("Refreshing native EGLConfig handle failed with error "+EGLContext.toHexString(EGL.eglGetError())+": "+eglDevice+", "+capsChosen+" of "+aConfig); - } - } - eglConfig = new EGLGraphicsConfiguration(eglScreen, capsChosen, capsRequested, null); - if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - Reusing chosenCaps: "+eglConfig); - } - } else { - eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( - capsRequested, capsRequested, null, eglScreen, aConfig.getVisualID(VIDType.NATIVE), false); - - if (null == eglConfig) { - throw new GLException("Couldn't create EGLGraphicsConfiguration from "+eglScreen); - } else if(DEBUG) { - System.err.println(getThreadName() + ": getEGLSurface - Chosen eglConfig: "+eglConfig); - } - } - return new WrappedSurface(eglConfig, EGL.EGL_NO_SURFACE, surface.getWidth(), surface.getHeight(), new EGLUpstreamSurfaceHook(surface)); - } static String getThreadName() { return Thread.currentThread().getName(); } @Override @@ -617,7 +560,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { throw new GLException("Non pbuffer not yet implemented"); } // PBuffer GLDrawable Creation - return new EGLPbufferDrawable(this, getEGLSurface(target)); + return new EGLPbufferDrawable(this, EGLWrappedSurface.get(target)); } @Override @@ -630,72 +573,34 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) { + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { + final boolean ownDevice; final EGLGraphicsDevice device; - if(createNewDevice) { - final EGLGraphicsDevice eglDeviceReq = (EGLGraphicsDevice) deviceReq; - device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID()); + if(createNewDevice || ! ( deviceReq instanceof EGLGraphicsDevice ) ) { + final long nativeDisplayID = ( deviceReq instanceof EGLGraphicsDevice) ? + ( (EGLGraphicsDevice) deviceReq ).getNativeDisplayID() : deviceReq.getHandle() ; + device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(nativeDisplayID, deviceReq.getConnection(), deviceReq.getUnitID()); + ownDevice = true; } else { device = (EGLGraphicsDevice) deviceReq; + ownDevice = false; } final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, 0); final EGLGraphicsConfiguration config = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false); if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } - return new WrappedSurface(config, 0, width, height, lifecycleHook); + return new WrappedSurface(config, 0, upstreamHook, ownDevice); } @Override public final ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) { - final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(requestedCaps, false, canCreateGLPbuffer(deviceReq)); - return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook); + final GLCapabilitiesImmutable chosenCaps = + GLGraphicsConfigurationUtil.fixDoubleBufferedGLCapabilities( + GLGraphicsConfigurationUtil.fixOffscreenGLCapabilities(requestedCaps, false, canCreateGLPbuffer(deviceReq)), false); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new EGLDummyUpstreamSurfaceHook(width, height)); } - private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() { - @Override - public final void create(ProxySurface s) { - if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) { - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); - if(0 == eglDevice.getHandle()) { - eglDevice.open(); - s.setImplBitfield(ProxySurface.OWN_DEVICE); - } - createPBufferSurfaceImpl(s, false); - if(DEBUG) { - System.err.println("EGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final void destroy(ProxySurface s) { - if( EGL.EGL_NO_SURFACE != s.getSurfaceHandle() ) { - final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) s.getGraphicsConfiguration(); - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) config.getScreen().getDevice(); - EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle()); - s.setSurfaceHandle(EGL.EGL_NO_SURFACE); - if( 0 != ( ProxySurface.OWN_DEVICE & s.getImplBitfield() ) ) { - eglDevice.close(); - } - if(DEBUG) { - System.err.println("EGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final int getWidth(ProxySurface s) { - return s.initialWidth; - } - @Override - public final int getHeight(ProxySurface s) { - return s.initialHeight; - } - @Override - public String toString() { - return "EGLSurfaceLifecycleHook[]"; - } - - }; /** * @param ms {@link MutableSurface} which dimensions and config are being used to create the pbuffer surface. @@ -704,7 +609,9 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { * @return the passed {@link MutableSurface} which now has the EGL pbuffer surface set as it's handle */ protected static MutableSurface createPBufferSurfaceImpl(MutableSurface ms, boolean useTexture) { - final EGLGraphicsConfiguration config = (EGLGraphicsConfiguration) ms.getGraphicsConfiguration(); + return null; + } + protected static long createPBufferSurfaceImpl(EGLGraphicsConfiguration config, int width, int height, boolean useTexture) { final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) config.getScreen().getDevice(); final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); final int texFormat; @@ -719,15 +626,14 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { System.out.println("Pbuffer config: " + config); } - final int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(ms.getWidth(), ms.getHeight(), texFormat); + final int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(width, height, texFormat); final long surf = EGL.eglCreatePbufferSurface(eglDevice.getHandle(), config.getNativeConfig(), attrs, 0); if (EGL.EGL_NO_SURFACE==surf) { - throw new GLException("Creation of window surface (eglCreatePbufferSurface) failed, dim "+ms.getWidth()+"x"+ms.getHeight()+", error 0x"+Integer.toHexString(EGL.eglGetError())); + throw new GLException("Creation of window surface (eglCreatePbufferSurface) failed, dim "+width+"x"+height+", "+eglDevice+", "+config+", error 0x"+Integer.toHexString(EGL.eglGetError())); } else if(DEBUG) { System.err.println("PBuffer setSurface result: eglSurface 0x"+Long.toHexString(surf)); } - ms.setSurfaceHandle(surf); - return ms; + return surf; } @Override @@ -736,7 +642,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { final EGLGraphicsDevice device = EGLDisplayUtil.eglCreateEGLGraphicsDevice(eglDeviceReq.getNativeDisplayID(), deviceReq.getConnection(), deviceReq.getUnitID()); final DefaultGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final EGLGraphicsConfiguration cfg = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, VisualIDHolder.VID_UNDEFINED, false); - return new WrappedSurface(cfg, windowHandle, 0, 0, upstream); + return new WrappedSurface(cfg, windowHandle, upstream, true); } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java new file mode 100644 index 000000000..b172d4f35 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDummyUpstreamSurfaceHook.java @@ -0,0 +1,49 @@ +package jogamp.opengl.egl; + +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; + +import com.jogamp.nativewindow.UpstreamSurfaceHookMutableSize; +import com.jogamp.nativewindow.egl.EGLGraphicsDevice; + +public class EGLDummyUpstreamSurfaceHook extends UpstreamSurfaceHookMutableSize { + /** + * @param width the initial width as returned by {@link NativeSurface#getWidth()} via {@link UpstreamSurfaceHook#getWidth(ProxySurface)}, + * not the actual dummy surface width. + * The latter is platform specific and small + * @param height the initial height as returned by {@link NativeSurface#getHeight()} via {@link UpstreamSurfaceHook#getHeight(ProxySurface)}, + * not the actual dummy surface height, + * The latter is platform specific and small + */ + public EGLDummyUpstreamSurfaceHook(int width, int height) { + super(width, height); + } + + @Override + public final void create(ProxySurface s) { + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); + if(0 == eglDevice.getHandle()) { + eglDevice.open(); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) { + s.setSurfaceHandle( EGLDrawableFactory.createPBufferSurfaceImpl((EGLGraphicsConfiguration)s.getGraphicsConfiguration(), 64, 64, false) ); + s.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + s.addUpstreamOptionBits(ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE); + } + + @Override + public final void destroy(ProxySurface s) { + if( s.containsUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ) ) { + final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) s.getGraphicsConfiguration().getScreen().getDevice(); + if( EGL.EGL_NO_SURFACE == s.getSurfaceHandle() ) { + throw new InternalError("Owns upstream surface, but no EGL surface: "+s); + } + EGL.eglDestroySurface(eglDevice.getHandle(), s.getSurfaceHandle()); + s.setSurfaceHandle(EGL.EGL_NO_SURFACE); + s.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + } + } +} diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java index 585638d21..84bd705db 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLExternalContext.java @@ -79,15 +79,4 @@ public class EGLExternalContext extends EGLContext { @Override protected void destroyImpl() throws GLException { } - - @Override - public void bindPbufferToTexture() { - throw new GLException("Should not call this"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Should not call this"); - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java index 70a570174..f857c6b5c 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGLCapabilities.java @@ -33,6 +33,8 @@ import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import com.jogamp.nativewindow.egl.EGLGraphicsDevice; + public class EGLGLCapabilities extends GLCapabilities { private long eglcfg; @@ -45,18 +47,18 @@ public class EGLGLCapabilities extends GLCapabilities { * @param eglcfg * @param eglcfgid * @param visualID native visualID if valid, otherwise VisualIDHolder.VID_UNDEFINED - * @param glp desired GLProfile, or null if determined by renderableType + * @param glp desired GLProfile * @param renderableType actual EGL renderableType * * May throw GLException if given GLProfile is not compatible w/ renderableType */ public EGLGLCapabilities(long eglcfg, int eglcfgid, int visualID, GLProfile glp, int renderableType) { - super( ( null != glp ) ? glp : getCompatible(renderableType) ); + super( glp ); this.eglcfg = eglcfg; this.eglcfgid = eglcfgid; if(!isCompatible(glp, renderableType)) { - throw new GLException("Incompatible "+glp+ - " with EGL-RenderableType["+renderableTypeToString(null, renderableType)+"]"); + throw new GLException("Requested GLProfile "+glp+ + " not compatible with EGL-RenderableType["+renderableTypeToString(null, renderableType)+"]"); } this.renderableType = renderableType; this.nativeVisualID = visualID; @@ -111,15 +113,15 @@ public class EGLGLCapabilities extends GLCapabilities { return false; } - public static GLProfile getCompatible(int renderableType) { - if(0 != (renderableType & EGL.EGL_OPENGL_ES2_BIT) && GLProfile.isAvailable(GLProfile.GLES2)) { - return GLProfile.get(GLProfile.GLES2); + public static GLProfile getCompatible(EGLGraphicsDevice device, int renderableType) { + if(0 != (renderableType & EGL.EGL_OPENGL_ES2_BIT) && GLProfile.isAvailable(device, GLProfile.GLES2)) { + return GLProfile.get(device, GLProfile.GLES2); } - if(0 != (renderableType & EGL.EGL_OPENGL_ES_BIT) && GLProfile.isAvailable(GLProfile.GLES1)) { - return GLProfile.get(GLProfile.GLES1); + if(0 != (renderableType & EGL.EGL_OPENGL_ES_BIT) && GLProfile.isAvailable(device, GLProfile.GLES1)) { + return GLProfile.get(device, GLProfile.GLES1); } if(0 != (renderableType & EGL.EGL_OPENGL_BIT)) { - return GLProfile.getDefault(); + return GLProfile.getDefault(device); } return null; } @@ -129,6 +131,7 @@ public class EGLGLCapabilities extends GLCapabilities { sink = new StringBuilder(); } boolean first=true; + sink.append("0x").append(Integer.toHexString(renderableType)).append(": "); if(0 != (renderableType & EGL.EGL_OPENGL_BIT)) { sink.append("GL"); first=false; } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 20102547d..7bf201238 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -37,8 +37,6 @@ package jogamp.opengl.egl; import java.nio.IntBuffer; -import java.util.ArrayList; -import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; @@ -85,7 +83,8 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple } final long cfg = EGLConfigId2EGLConfig(dpy, cfgID); if(0 < cfg) { - final EGLGLCapabilities caps = EGLConfig2Capabilities(capsRequested.getGLProfile(), dpy, cfg, false, capsRequested.isOnscreen(), capsRequested.isPBuffer(), false); + final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsRequested); + final EGLGLCapabilities caps = EGLConfig2Capabilities((EGLGraphicsDevice)absDevice, capsRequested.getGLProfile(), cfg, winattrmask, false); return new EGLGraphicsConfiguration(absScreen, caps, capsRequested, new DefaultGLCapabilitiesChooser()); } return null; @@ -129,11 +128,28 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple return configs.get(0); } - static int EGLConfigDrawableTypeBits(final long display, final long config) { + public static boolean isEGLConfigValid(long display, long config) { + if(0 == config) { + return false; + } + final IntBuffer val = Buffers.newDirectIntBuffer(1); + + // get the configID + if(!EGL.eglGetConfigAttrib(display, config, EGL.EGL_CONFIG_ID, val)) { + final int eglErr = EGL.eglGetError(); + if(DEBUG) { + System.err.println("Info: Couldn't retrieve EGL ConfigID for config "+toHexString(config)+", error "+toHexString(eglErr)); + } + return false; + } + return true; + } + + static int EGLConfigDrawableTypeBits(final EGLGraphicsDevice device, final long config) { int val = 0; int[] stype = new int[1]; - if(! EGL.eglGetConfigAttrib(display, config, EGL.EGL_SURFACE_TYPE, stype, 0)) { + if(! EGL.eglGetConfigAttrib(device.getHandle(), config, EGL.EGL_SURFACE_TYPE, stype, 0)) { throw new GLException("Could not determine EGL_SURFACE_TYPE"); } @@ -144,34 +160,23 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple val |= GLGraphicsConfigurationUtil.BITMAP_BIT; } if ( 0 != ( stype[0] & EGL.EGL_PBUFFER_BIT ) ) { - val |= GLGraphicsConfigurationUtil.PBUFFER_BIT; + val |= GLGraphicsConfigurationUtil.PBUFFER_BIT | + GLGraphicsConfigurationUtil.FBO_BIT; } - return val; } - public static EGLGLCapabilities EGLConfig2Capabilities(GLProfile glp, long display, long config, - boolean relaxed, boolean onscreen, boolean usePBuffer, boolean forceTransparentFlag) { - List<GLCapabilitiesImmutable> bucket = new ArrayList<GLCapabilitiesImmutable>(); - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, false); - if( EGLConfig2Capabilities(bucket, glp, display, config, winattrmask, forceTransparentFlag) ) { - return (EGLGLCapabilities) bucket.get(0); - } else if ( relaxed && EGLConfig2Capabilities(bucket, glp, display, config, GLGraphicsConfigurationUtil.ALL_BITS, forceTransparentFlag) ) { - return (EGLGLCapabilities) bucket.get(0); - } - return null; - } - - public static boolean EGLConfig2Capabilities(List<GLCapabilitiesImmutable> capsBucket, - GLProfile glp, long display, long config, - int winattrmask, boolean forceTransparentFlag) { - final int allDrawableTypeBits = EGLConfigDrawableTypeBits(display, config); - final int drawableTypeBits = winattrmask & allDrawableTypeBits; - - if( 0 == drawableTypeBits ) { - return false; - } - + /** + * @param device + * @param glp desired GLProfile, may be null + * @param config + * @param winattrmask + * @param forceTransparentFlag + * @return + */ + public static EGLGLCapabilities EGLConfig2Capabilities(EGLGraphicsDevice device, GLProfile glp, long config, + int winattrmask, boolean forceTransparentFlag) { + final long display = device.getHandle(); final IntBuffer val = Buffers.newDirectIntBuffer(1); final int cfgID; final int rType; @@ -183,7 +188,7 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple // FIXME: this happens on a ATI PC Emulation .. System.err.println("EGL couldn't retrieve ConfigID for config "+toHexString(config)+", error "+toHexString(EGL.eglGetError())); } - return false; + return null; } cfgID = val.get(0); @@ -191,10 +196,10 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple if(DEBUG) { System.err.println("EGL couldn't retrieve EGL_RENDERABLE_TYPE for config "+toHexString(config)+", error "+toHexString(EGL.eglGetError())); } - return false; + return null; } rType = val.get(0); - + if(EGL.eglGetConfigAttrib(display, config, EGL.EGL_NATIVE_VISUAL_ID, val)) { visualID = val.get(0); } else { @@ -203,12 +208,22 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple EGLGLCapabilities caps = null; try { + if(null == glp) { + glp = EGLGLCapabilities.getCompatible(device, rType); + } + if(!EGLGLCapabilities.isCompatible(glp, rType)) { + if(DEBUG) { + System.err.println("config "+toHexString(config)+": Requested GLProfile "+glp+ + " not compatible with EGL-RenderableType["+EGLGLCapabilities.renderableTypeToString(null, rType)+"]"); + } + return null; + } caps = new EGLGLCapabilities(config, cfgID, visualID, glp, rType); } catch (GLException gle) { if(DEBUG) { System.err.println("config "+toHexString(config)+": "+gle); } - return false; + return null; } if(EGL.eglGetConfigAttrib(display, config, EGL.EGL_CONFIG_CAVEAT, val)) { @@ -270,7 +285,17 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple if(EGL.eglGetConfigAttrib(display, config, EGL.EGL_DEPTH_SIZE, val)) { caps.setDepthBits(val.get(0)); } - return GLGraphicsConfigurationUtil.addGLCapabilitiesPermutations(capsBucket, caps, drawableTypeBits ); + + // Since the passed GLProfile may be null, + // we use EGL_RENDERABLE_TYPE derived profile as created in the EGLGLCapabilities constructor. + final int availableTypeBits = EGLConfigDrawableTypeBits(device, config); + final int drawableTypeBits = winattrmask & availableTypeBits; + + if( 0 == drawableTypeBits ) { + return null; + } + + return (EGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, caps); } public static int[] GLCapabilities2AttribList(GLCapabilitiesImmutable caps) { @@ -278,7 +303,19 @@ public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration imple int idx=0; attrs[idx++] = EGL.EGL_SURFACE_TYPE; - attrs[idx++] = caps.isOnscreen() ? ( EGL.EGL_WINDOW_BIT ) : ( caps.isPBuffer() ? EGL.EGL_PBUFFER_BIT : EGL.EGL_PIXMAP_BIT ) ; + final int surfaceType; + if( caps.isOnscreen() ) { + surfaceType = EGL.EGL_WINDOW_BIT; + } else if( caps.isFBO() ) { + surfaceType = EGL.EGL_PBUFFER_BIT; // native replacement! + } else if( caps.isPBuffer() ) { + surfaceType = EGL.EGL_PBUFFER_BIT; + } else if( caps.isBitmap() ) { + surfaceType = EGL.EGL_PIXMAP_BIT; + } else { + throw new GLException("no surface type set in caps: "+caps); + } + attrs[idx++] = surfaceType; attrs[idx++] = EGL.EGL_RED_SIZE; attrs[idx++] = caps.getRedBits(); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java index 72dea9ead..e72255108 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfigurationFactory.java @@ -207,7 +207,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact throw new GLException("Graphics configuration get all configs (eglGetConfigs) call failed, error "+toHexString(EGL.eglGetError())); } if (numConfigs.get(0) > 0) { - availableCaps = eglConfigs2GLCaps(null, eglDisplay, configs, numConfigs.get(0), GLGraphicsConfigurationUtil.ALL_BITS, false); + availableCaps = eglConfigs2GLCaps(eglDevice, null, configs, numConfigs.get(0), GLGraphicsConfigurationUtil.ALL_BITS, false); if( null != availableCaps && availableCaps.size() > 1) { Collections.sort(availableCaps, EglCfgIDComparator); } @@ -250,7 +250,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact final EGLDrawableFactory factory = (EGLDrawableFactory) GLDrawableFactory.getEGLFactory(); capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLContext.isFBOAvailable(absDevice, glp), factory.canCreateGLPbuffer(absDevice) ); - EGLGraphicsConfiguration res = eglChooseConfig(eglDevice.getHandle(), capsChosen, capsReq, chooser, absScreen, nativeVisualID, forceTransparentFlag); + EGLGraphicsConfiguration res = eglChooseConfig(eglDevice, capsChosen, capsReq, chooser, absScreen, nativeVisualID, forceTransparentFlag); if(null==res) { if(DEBUG) { System.err.println("eglChooseConfig failed with given capabilities "+capsChosen); @@ -274,7 +274,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact if(DEBUG) { System.err.println("trying fixed caps (1): "+fixedCaps); } - res = eglChooseConfig(eglDevice.getHandle(), fixedCaps, capsReq, chooser, absScreen, nativeVisualID, false); + res = eglChooseConfig(eglDevice, fixedCaps, capsReq, chooser, absScreen, nativeVisualID, false); } if(null==res) { // @@ -292,7 +292,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact if(DEBUG) { System.err.println("trying fixed caps (2): "+fixedCaps); } - res = eglChooseConfig(eglDevice.getHandle(), fixedCaps, capsReq, chooser, absScreen, nativeVisualID, false); + res = eglChooseConfig(eglDevice, fixedCaps, capsReq, chooser, absScreen, nativeVisualID, false); } if(null==res) { // @@ -312,7 +312,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact if(DEBUG) { System.err.println("trying fixed caps (3): "+fixedCaps); } - res = eglChooseConfig(eglDevice.getHandle(), fixedCaps, capsReq, chooser, absScreen, nativeVisualID, false); + res = eglChooseConfig(eglDevice, fixedCaps, capsReq, chooser, absScreen, nativeVisualID, false); } if(null==res) { throw new GLException("Graphics configuration failed [direct caps, eglGetConfig/chooser and fixed-caps(1-3)]"); @@ -324,15 +324,15 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact return res; } - static EGLGraphicsConfiguration eglChooseConfig(long eglDisplay, + + static EGLGraphicsConfiguration eglChooseConfig(EGLGraphicsDevice device, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID, boolean forceTransparentFlag) { + final long eglDisplay = device.getHandle(); final GLProfile glp = capsChosen.getGLProfile(); - final boolean onscreen = capsChosen.isOnscreen(); - final boolean usePBuffer = capsChosen.isPBuffer(); - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, false); + final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen); List<GLCapabilitiesImmutable> availableCaps = null; int recommendedIndex = -1; long recommendedEGLConfig = -1; @@ -345,7 +345,12 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact throw new GLException("EGLGraphicsConfiguration.eglChooseConfig: Get maxConfigs (eglGetConfigs) no configs"); } if (DEBUG) { - System.err.println("EGLGraphicsConfiguration.eglChooseConfig: eglChooseConfig eglDisplay "+toHexString(eglDisplay)+", nativeVisualID "+toHexString(nativeVisualID)+", onscreen "+onscreen+", usePBuffer "+usePBuffer+", "+capsChosen+", numConfigs "+numConfigs.get(0)); + System.err.println("EGLGraphicsConfiguration.eglChooseConfig: eglChooseConfig eglDisplay "+toHexString(eglDisplay)+ + ", nativeVisualID "+toHexString(nativeVisualID)+ + ", capsChosen "+capsChosen+", winbits "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrmask).toString()+ + ", fboAvail "+GLContext.isFBOAvailable(device, glp)+ + ", device "+device+", "+device.getUniqueID()+ + ", numConfigs "+numConfigs.get(0)); } final IntBuffer attrs = Buffers.newDirectIntBuffer(EGLGraphicsConfiguration.GLCapabilities2AttribList(capsChosen)); @@ -359,7 +364,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact System.err.println("EGLGraphicsConfiguration.eglChooseConfig: #1 eglChooseConfig: false"); } } else if (numConfigs.get(0) > 0) { - availableCaps = eglConfigs2GLCaps(glp, eglDisplay, configs, numConfigs.get(0), winattrmask, forceTransparentFlag); + availableCaps = eglConfigs2GLCaps(device, glp, configs, numConfigs.get(0), winattrmask, forceTransparentFlag); if(availableCaps.size() > 0) { recommendedEGLConfig = configs.get(0); recommendedIndex = 0; @@ -384,7 +389,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact throw new GLException("EGLGraphicsConfiguration.eglChooseConfig: #2 Get all configs (eglGetConfigs) call failed, error "+toHexString(EGL.eglGetError())); } if (numConfigs.get(0) > 0) { - availableCaps = eglConfigs2GLCaps(glp, eglDisplay, configs, numConfigs.get(0), winattrmask, forceTransparentFlag); + availableCaps = eglConfigs2GLCaps(device, glp, configs, numConfigs.get(0), winattrmask, forceTransparentFlag); } } @@ -392,7 +397,7 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact if(DEBUG) { // FIXME: this happens on a ATI PC Emulation .. System.err.println("EGLGraphicsConfiguration.eglChooseConfig: #2 Graphics configuration 1st choice and 2nd choice failed - no configs"); - availableCaps = eglConfigs2GLCaps(glp, eglDisplay, configs, numConfigs.get(0), GLGraphicsConfigurationUtil.ALL_BITS, forceTransparentFlag); + availableCaps = eglConfigs2GLCaps(device, glp, configs, numConfigs.get(0), GLGraphicsConfigurationUtil.ALL_BITS, forceTransparentFlag); printCaps("AllCaps", availableCaps, System.err); } return null; @@ -433,18 +438,22 @@ public class EGLGraphicsConfigurationFactory extends GLGraphicsConfigurationFact return null; } final EGLGLCapabilities chosenCaps = (EGLGLCapabilities) availableCaps.get(chosenIndex); + final EGLGraphicsConfiguration res = new EGLGraphicsConfiguration(absScreen, chosenCaps, capsRequested, chooser); if (DEBUG) { - System.err.println("EGLGraphicsConfiguration.eglChooseConfig: X chosen :"+chosenIndex+", eglConfig: "+toHexString(chosenCaps.getEGLConfig())+", "+chosenCaps); + System.err.println("EGLGraphicsConfiguration.eglChooseConfig: X chosen :"+chosenIndex+", eglConfig: "+toHexString(chosenCaps.getEGLConfig())+": "+res); } - return new EGLGraphicsConfiguration(absScreen, chosenCaps, capsRequested, chooser); + return res; } - static List<GLCapabilitiesImmutable> eglConfigs2GLCaps(GLProfile glp, long eglDisplay, PointerBuffer configs, int num, int winattrmask, boolean forceTransparentFlag) { - List<GLCapabilitiesImmutable> caps = new ArrayList<GLCapabilitiesImmutable>(num); + static List<GLCapabilitiesImmutable> eglConfigs2GLCaps(EGLGraphicsDevice device, GLProfile glp, PointerBuffer configs, int num, int winattrmask, boolean forceTransparentFlag) { + List<GLCapabilitiesImmutable> bucket = new ArrayList<GLCapabilitiesImmutable>(num); for(int i=0; i<num; i++) { - EGLGraphicsConfiguration.EGLConfig2Capabilities(caps, glp, eglDisplay, configs.get(i), winattrmask, forceTransparentFlag); + final GLCapabilitiesImmutable caps = EGLGraphicsConfiguration.EGLConfig2Capabilities(device, glp, configs.get(i), winattrmask, forceTransparentFlag); + if(null != caps) { + bucket.add(caps); + } } - return caps; + return bucket; } static void printCaps(String prefix, List<GLCapabilitiesImmutable> caps, PrintStream out) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java index eae47fa92..325ad6142 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenContext.java @@ -41,16 +41,5 @@ public class EGLOnscreenContext extends EGLContext { public EGLOnscreenContext(EGLOnscreenDrawable drawable, GLContext shareWith) { super(drawable, shareWith); } - - @Override - public void bindPbufferToTexture() { - throw new GLException("Should not call this"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Should not call this"); - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java index d54057775..6440cf1e5 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java @@ -54,8 +54,8 @@ public class EGLOnscreenDrawable extends EGLDrawable { } @Override - protected long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle) { + protected long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle) { return EGL.eglCreateWindowSurface(config.getScreen().getDevice().getHandle(), config.getNativeConfig(), nativeSurfaceHandle, null); - } + } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java index 7175d516f..bb9eeb892 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferContext.java @@ -46,15 +46,5 @@ public class EGLPbufferContext extends EGLContext { public int getFloatingPointMode() { return 0; // FIXME ?? } - - @Override - public void bindPbufferToTexture() { - throw new GLException("Not yet implemented"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Not yet implemented"); - } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java index 4a36625bd..eb7e320c8 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java @@ -52,12 +52,8 @@ public class EGLPbufferDrawable extends EGLDrawable { } @Override - protected long createSurface(EGLGraphicsConfiguration config, long nativeSurfaceHandle) { - final MutableSurface ms = (MutableSurface)getNativeSurface(); - if(config != ms.getGraphicsConfiguration()) { - throw new InternalError("Not same: "+config.hashCode()+", "+ms.getGraphicsConfiguration()+": "+config+", "+ms.getGraphicsConfiguration()); - } - return EGLDrawableFactory.createPBufferSurfaceImpl(ms, useTexture).getSurfaceHandle(); + protected long createSurface(EGLGraphicsConfiguration config, int width, int height, long nativeSurfaceHandle) { + return EGLDrawableFactory.createPBufferSurfaceImpl(config, width, height, false); } @Override diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java index 42c6e100e..342c4c417 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLUpstreamSurfaceHook.java @@ -1,38 +1,163 @@ package jogamp.opengl.egl; +import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.DefaultGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.UpstreamSurfaceHook; +import javax.media.nativewindow.VisualIDHolder.VIDType; +import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; import com.jogamp.nativewindow.egl.EGLGraphicsDevice; -public class EGLUpstreamSurfaceHook implements ProxySurface.UpstreamSurfaceHook { +public class EGLUpstreamSurfaceHook implements UpstreamSurfaceHook.MutableSize { + protected static final boolean DEBUG = EGLDrawableFactory.DEBUG; private final NativeSurface upstreamSurface; + private final UpstreamSurfaceHook.MutableSize upstreamSurfaceHookMutableSize; public EGLUpstreamSurfaceHook(NativeSurface upstream) { upstreamSurface = upstream; + if(upstreamSurface instanceof ProxySurface) { + final UpstreamSurfaceHook ush = ((ProxySurface)upstreamSurface).getUpstreamSurfaceHook(); + if(ush instanceof UpstreamSurfaceHook.MutableSize) { + // offscreen NativeSurface w/ MutableSize (default) + upstreamSurfaceHookMutableSize = (UpstreamSurfaceHook.MutableSize) ush; + } else { + upstreamSurfaceHookMutableSize = null; + } + } else { + upstreamSurfaceHookMutableSize = null; + } } public final NativeSurface getUpstreamSurface() { return upstreamSurface; } + static String getThreadName() { return Thread.currentThread().getName(); } + + public final void setSize(int width, int height) { + if(null != upstreamSurfaceHookMutableSize) { + upstreamSurfaceHookMutableSize.setSize(width, height); + } + } + @Override public final void create(ProxySurface surface) { + final String dbgPrefix; + if(DEBUG) { + dbgPrefix = getThreadName() + ": EGLUpstreamSurfaceHook.create("+surface.getClass().getSimpleName()+"): "; + System.err.println(dbgPrefix+this); + } else { + dbgPrefix = null; + } + if(upstreamSurface instanceof ProxySurface) { + // propagate createNotify(..) so upstreamSurface will be created ((ProxySurface)upstreamSurface).createNotify(); - if(NativeSurface.LOCK_SURFACE_NOT_READY >= upstreamSurface.lockSurface()) { - throw new GLException("Could not lock: "+upstreamSurface); + } + + // lock upstreamSurface, so it can be used in case EGLDisplay is derived from it! + if(NativeSurface.LOCK_SURFACE_NOT_READY >= upstreamSurface.lockSurface()) { + throw new GLException("Could not lock: "+upstreamSurface); + } + try { + evalUpstreamSurface(dbgPrefix, surface); + } finally { + upstreamSurface.unlockSurface(); + } + } + + private final void evalUpstreamSurface(String dbgPrefix, ProxySurface surface) { + // + // evaluate nature of upstreamSurface, may create EGL instances if required + // + + boolean isEGLSurfaceValid = true; // assume yes + + final AbstractGraphicsConfiguration aConfig = upstreamSurface.getGraphicsConfiguration(); + final AbstractGraphicsDevice aDevice = aConfig.getScreen().getDevice(); + + final EGLGraphicsDevice eglDevice; + if( aDevice instanceof EGLGraphicsDevice ) { + eglDevice = (EGLGraphicsDevice) aDevice; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing eglDevice: "+eglDevice); + } + if(EGL.EGL_NO_DISPLAY == eglDevice.getHandle()) { + eglDevice.open(); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + } else { + eglDevice = EGLDisplayUtil.eglCreateEGLGraphicsDevice(upstreamSurface); + isEGLSurfaceValid = false; + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_DEVICE ); + } + + final GLCapabilitiesImmutable capsRequested = (GLCapabilitiesImmutable) aConfig.getRequestedCapabilities(); + final EGLGraphicsConfiguration eglConfig; + if( aConfig instanceof EGLGraphicsConfiguration ) { + // Config is already in EGL type - reuse .. + final EGLGLCapabilities capsChosen = (EGLGLCapabilities) aConfig.getChosenCapabilities(); + if( !isEGLSurfaceValid || !EGLGraphicsConfiguration.isEGLConfigValid(eglDevice.getHandle(), capsChosen.getEGLConfig()) ) { + // 'refresh' the native EGLConfig handle + capsChosen.setEGLConfig(EGLGraphicsConfiguration.EGLConfigId2EGLConfig(eglDevice.getHandle(), capsChosen.getEGLConfigID())); + if( 0 == capsChosen.getEGLConfig() ) { + throw new GLException("Refreshing native EGLConfig handle failed with error "+EGLContext.toHexString(EGL.eglGetError())+": "+eglDevice+", "+capsChosen+" of "+aConfig); + } + final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex()); + eglConfig = new EGLGraphicsConfiguration(eglScreen, capsChosen, capsRequested, null); + if(DEBUG) { + System.err.println(dbgPrefix+"Refreshing eglConfig: "+eglConfig); + } + isEGLSurfaceValid = false; + } else { + eglConfig = (EGLGraphicsConfiguration) aConfig; + if(DEBUG) { + System.err.println(dbgPrefix+"Reusing eglConfig: "+eglConfig); + } + } + } else { + final AbstractGraphicsScreen eglScreen = new DefaultGraphicsScreen(eglDevice, aConfig.getScreen().getIndex()); + eglConfig = EGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( + capsRequested, capsRequested, null, eglScreen, aConfig.getVisualID(VIDType.NATIVE), false); + + if (null == eglConfig) { + throw new GLException("Couldn't create EGLGraphicsConfiguration from "+eglScreen); + } else if(DEBUG) { + System.err.println(dbgPrefix+"Chosen eglConfig: "+eglConfig); } + isEGLSurfaceValid = false; } - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); - eglDevice.open(); + surface.setGraphicsConfiguration(eglConfig); + + if(isEGLSurfaceValid) { + isEGLSurfaceValid = EGLDrawable.isValidEGLSurface(eglDevice.getHandle(), upstreamSurface.getSurfaceHandle()); + } + if(isEGLSurfaceValid) { + surface.setSurfaceHandle(upstreamSurface.getSurfaceHandle()); + surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); + if(DEBUG) { + System.err.println(dbgPrefix+"Fin: Already valid EGL surface - use as-is: "+upstreamSurface); + } + } else { + surface.setSurfaceHandle(EGL.EGL_NO_SURFACE); + surface.addUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); // create/destroy in EGLDrawable + if(DEBUG) { + System.err.println(dbgPrefix+"Fin: EGL surface n/a - TBD: "+upstreamSurface); + } + } } @Override public final void destroy(ProxySurface surface) { - final EGLGraphicsDevice eglDevice = (EGLGraphicsDevice) surface.getGraphicsConfiguration().getScreen().getDevice(); - eglDevice.close(); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLUpstreamSurfaceHook.destroy("+surface.getClass().getSimpleName()+"): "+this); + } + surface.clearUpstreamOptionBits( ProxySurface.OPT_PROXY_OWNS_UPSTREAM_SURFACE ); if(upstreamSurface instanceof ProxySurface) { - upstreamSurface.unlockSurface(); ((ProxySurface)upstreamSurface).destroyNotify(); } } @@ -49,8 +174,8 @@ public class EGLUpstreamSurfaceHook implements ProxySurface.UpstreamSurfaceHook @Override public String toString() { - final String us_s = null != upstreamSurface ? ( upstreamSurface.getClass().getName() + ": " + upstreamSurface ) : "nil"; - return "EGLUpstreamSurfaceHook[upstream: "+us_s+"]"; + final String us_s = null != upstreamSurface ? ( upstreamSurface.getClass().getName() + ": 0x" + Long.toHexString(upstreamSurface.getSurfaceHandle()) ) : "nil"; + return "EGLUpstreamSurfaceHook[ "+ upstreamSurface.getWidth() + "x" + upstreamSurface.getHeight() + ", " + us_s+ "]"; } } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java new file mode 100644 index 000000000..b36303392 --- /dev/null +++ b/src/jogl/classes/jogamp/opengl/egl/EGLWrappedSurface.java @@ -0,0 +1,26 @@ +package jogamp.opengl.egl; + +import javax.media.nativewindow.NativeSurface; + +import jogamp.nativewindow.WrappedSurface; + +public class EGLWrappedSurface extends WrappedSurface { + + public static EGLWrappedSurface get(NativeSurface surface) { + if(surface instanceof EGLWrappedSurface) { + return (EGLWrappedSurface)surface; + } + return new EGLWrappedSurface(surface); + } + + public EGLWrappedSurface(NativeSurface surface) { + super(surface.getGraphicsConfiguration(), EGL.EGL_NO_SURFACE, new EGLUpstreamSurfaceHook(surface), false /* tbd in UpstreamSurfaceHook */); + if(EGLDrawableFactory.DEBUG) { + System.err.println("EGLWrappedSurface.ctor(): "+this); + } + } + + public final NativeSurface getUpstreamSurface() { + return ((EGLUpstreamSurfaceHook)super.getUpstreamSurfaceHook()).getUpstreamSurface(); + } +} diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 82525cfde..ec29558d1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -49,6 +49,8 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.nativewindow.ProxySurface; +import javax.media.opengl.GL; +import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; @@ -57,6 +59,7 @@ import javax.media.opengl.GLProfile; import jogamp.nativewindow.macosx.OSXUtil; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLFBODrawableImpl; import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -75,9 +78,11 @@ public abstract class MacOSXCGLContext extends GLContextImpl boolean isNSContext(); long create(long share, int ctp, int major, int minor); boolean destroy(long ctx); + boolean contextRealized(boolean realized); boolean copyImpl(long src, int mask); boolean makeCurrent(long ctx); boolean release(long ctx); + boolean detachPBuffer(); boolean setSwapInterval(int interval); boolean swapBuffers(); } @@ -278,7 +283,24 @@ public abstract class MacOSXCGLContext extends GLContextImpl throw new GLException("Error destroying OpenGL Context: "+this); } } + + @Override + protected void contextRealized(boolean realized) { + // context stuff depends on drawable stuff + if(realized) { + super.contextRealized(true); // 1) init drawable stuff + impl.contextRealized(true); // 2) init context stuff + } else { + impl.contextRealized(false); // 1) free context stuff + super.contextRealized(false); // 2) free drawable stuff + } + } + + /* pp */ void detachPBuffer() { + impl.detachPBuffer(); + } + @Override protected void copyImpl(GLContext source, int mask) throws GLException { if( isNSContext() != ((MacOSXCGLContext)source).isNSContext() ) { @@ -364,16 +386,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl throw new GLException("Should not call this"); } - @Override - public void bindPbufferToTexture() { - throw new GLException("Should not call this"); - } - - @Override - public void releasePbufferFromTexture() { - throw new GLException("Should not call this"); - } - // Support for "mode switching" as described in MacOSXCGLDrawable public void setOpenGLMode(GLBackendType mode) { if (mode == openGLMode) { @@ -420,317 +432,486 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { - long nsOpenGLLayer = 0; - long nsOpenGLLayerPFmt = 0; - float screenVSyncTimeout; // microSec - int vsyncTimeout; // microSec - for nsOpenGLLayer mode - - @Override - public boolean isNSContext() { return true; } - - @Override - public long create(long share, int ctp, int major, int minor) { - long ctx = 0; - final long nsViewHandle; - if(drawable instanceof MacOSXCGLDrawable) { - // we allow null here! (special pbuffer case) - nsViewHandle = ((MacOSXCGLDrawable)MacOSXCGLContext.this.drawable).getNSViewHandle(); - } else { - // we only allow a valid NSView here - final long aHandle = drawable.getHandle(); - if( OSXUtil.isNSView(aHandle) ) { - nsViewHandle = aHandle; - } else { - throw new RuntimeException("Anonymous drawable instance's handle not of type NSView: "+drawable.getClass().getName()+", "+drawable); - } - } - final NativeSurface surface = drawable.getNativeSurface(); - final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration(); - final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - - boolean allowIncompleteView = null != backingLayerHost; - if( !allowIncompleteView && surface instanceof ProxySurface ) { - allowIncompleteView = 0 != ( ProxySurface.INVISIBLE_WINDOW & ((ProxySurface)surface).getImplBitfield() ) ; - } - final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); - long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); - if (pixelFormat == 0) { - if(DEBUG) { - System.err.println("Unable to allocate pixel format with requested GLCapabilities: "+chosenCaps); - } - return 0; - } - config.setChosenPixelFormat(pixelFormat); - int sRefreshRate = CGL.getScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex()); - screenVSyncTimeout = 1000000f / sRefreshRate; - if(DEBUG) { - System.err.println("NS create OSX>=lion "+isLionOrLater); - System.err.println("NS create allowIncompleteView: "+allowIncompleteView); - System.err.println("NS create backingLayerHost: "+backingLayerHost); - System.err.println("NS create share: "+share); - System.err.println("NS create chosenCaps: "+chosenCaps); - System.err.println("NS create pixelFormat: "+toHexString(pixelFormat)); - System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); - System.err.println("NS create drawable NSView-handle: "+toHexString(nsViewHandle)); - System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros"); - // Thread.dumpStack(); - } - try { - int[] viewNotReady = new int[1]; - // Try to allocate a context with this - ctx = CGL.createContext(share, - nsViewHandle, allowIncompleteView, - pixelFormat, - chosenCaps.isBackgroundOpaque(), - viewNotReady, 0); - if (0 == ctx) { - if(DEBUG) { - System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); - } - return 0; - } + private OffscreenLayerSurface backingLayerHost = null; + private long nsOpenGLLayer = 0; + private long nsOpenGLLayerPFmt = 0; + private float screenVSyncTimeout; // microSec + private int vsyncTimeout; // microSec - for nsOpenGLLayer mode + private int lastWidth=0, lastHeight=0; // allowing to detect size change + private long lastPBufferHandle = 0; // allowing to detect pbuffer recreation + + @Override + public boolean isNSContext() { return true; } + + @Override + public long create(long share, int ctp, int major, int minor) { + long ctx = 0; + final NativeSurface surface = drawable.getNativeSurface(); + final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration(); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final long nsViewHandle; + final boolean isPBuffer; + final boolean isFBO; + if(drawable instanceof GLFBODrawableImpl) { + nsViewHandle = 0; + isPBuffer = false; + isFBO = true; + if(DEBUG) { + System.err.println("NS create GLFBODrawableImpl drawable: isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + } else if(drawable instanceof MacOSXCGLDrawable) { + // we allow null here! (special pbuffer case) + nsViewHandle = ((MacOSXCGLDrawable)MacOSXCGLContext.this.drawable).getNSViewHandle(); + isPBuffer = CGL.isNSOpenGLPixelBuffer(drawable.getHandle()); + isFBO = false; + if(DEBUG) { + System.err.println("NS create MacOSXCGLDrawable drawable handle isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + } else { + // we only allow a valid NSView here + final long drawableHandle = drawable.getHandle(); + final boolean isNSView = OSXUtil.isNSView(drawableHandle); + final boolean isNSWindow = OSXUtil.isNSWindow(drawableHandle); + isPBuffer = CGL.isNSOpenGLPixelBuffer(drawableHandle); + isFBO = false; - if (!chosenCaps.isPBuffer() && !chosenCaps.isBackgroundOpaque()) { - // Set the context opacity - CGL.setContextOpacity(ctx, 0); + if(DEBUG) { + System.err.println("NS create Anonymous drawable handle "+toHexString(drawableHandle)+": isNSView "+isNSView+", isNSWindow "+isNSWindow+", isFBO "+isFBO+", isPBuffer "+isPBuffer+", "+drawable.getClass().getName()+",\n\t"+drawable); + } + if( isNSView ) { + nsViewHandle = drawableHandle; + } else if( isNSWindow ) { + nsViewHandle = OSXUtil.GetNSView(drawableHandle); + } else if( isPBuffer ) { + nsViewHandle = 0; + } else { + throw new RuntimeException("Anonymous drawable instance's handle neither NSView, NSWindow nor PBuffer: "+toHexString(drawableHandle)+", "+drawable.getClass().getName()+",\n\t"+drawable); + } } + backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - GLCapabilitiesImmutable fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); + boolean allowIncompleteView = null != backingLayerHost; + if( !allowIncompleteView && surface instanceof ProxySurface ) { + allowIncompleteView = ((ProxySurface)surface).containsUpstreamOptionBits( ProxySurface.OPT_UPSTREAM_WINDOW_INVISIBLE ); + } + long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); + if (pixelFormat == 0) { + if(DEBUG) { + System.err.println("Unable to allocate pixel format with requested GLCapabilities: "+chosenCaps); + } + return 0; + } + GLCapabilities fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); + if(chosenCaps.isOnscreen() || !fixedCaps.isPBuffer()) { + // not handled, so copy them + fixedCaps.setFBO(chosenCaps.isFBO()); + fixedCaps.setPBuffer(chosenCaps.isPBuffer()); + fixedCaps.setBitmap(chosenCaps.isBitmap()); + fixedCaps.setOnscreen(chosenCaps.isOnscreen()); + } fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); - config.setChosenCapabilities(fixedCaps); + int sRefreshRate = OSXUtil.GetScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex()); + screenVSyncTimeout = 1000000f / sRefreshRate; if(DEBUG) { + System.err.println("NS create OSX>=lion "+isLionOrLater); + System.err.println("NS create allowIncompleteView: "+allowIncompleteView); + System.err.println("NS create backingLayerHost: "+backingLayerHost); + System.err.println("NS create share: "+share); + System.err.println("NS create drawable type: "+drawable.getClass().getName()); + System.err.println("NS create drawable handle: isPBuffer "+isPBuffer+", isFBO "+isFBO); + System.err.println("NS create pixelFormat: "+toHexString(pixelFormat)); + System.err.println("NS create chosenCaps: "+chosenCaps); System.err.println("NS create fixedCaps: "+fixedCaps); + System.err.println("NS create drawable native-handle: "+toHexString(drawable.getHandle())); + System.err.println("NS create drawable NSView-handle: "+toHexString(nsViewHandle)); + System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros"); + // Thread.dumpStack(); } if(fixedCaps.isPBuffer()) { - // Must now associate the pbuffer with our newly-created context - CGL.setContextPBuffer(ctx, drawable.getHandle()); + if(!isPBuffer) { + throw new InternalError("fixedCaps is PBuffer, handle not: "+drawable); + } + } else { + if(isPBuffer) { + throw new InternalError("handle is PBuffer, fixedCaps not: "+drawable); + } } - // - // handled layered surface - // + config.setChosenCapabilities(fixedCaps); + /** if(null != backingLayerHost) { - nsOpenGLLayerPFmt = pixelFormat; - pixelFormat = 0; - final int texWidth, texHeight; - if(drawable instanceof MacOSXPbufferCGLDrawable) { - final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; - texWidth = osxPDrawable.getTextureWidth(); - texHeight = osxPDrawable.getTextureHeight(); - } else { - texWidth = drawable.getWidth(); - texHeight = drawable.getHeight(); + backingLayerHost.setChosenCapabilities(fixedCaps); + } */ + + try { + int[] viewNotReady = new int[1]; + // Try to allocate a context with this + ctx = CGL.createContext(share, + nsViewHandle, allowIncompleteView, + pixelFormat, + chosenCaps.isBackgroundOpaque(), + viewNotReady, 0); + if (0 == ctx) { + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); + } + return 0; } - if(0>=texWidth || 0>=texHeight || !drawable.isRealized()) { - throw new GLException("Drawable not realized yet or invalid texture size, texSize "+texWidth+"x"+texHeight+", "+drawable); + + if(null != backingLayerHost) { + nsOpenGLLayerPFmt = pixelFormat; + pixelFormat = 0; } - nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, drawable.getHandle(), fixedCaps.isBackgroundOpaque(), texWidth, texHeight); - if (DEBUG) { - System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", texSize "+texWidth+"x"+texHeight+", "+drawable); + + if (chosenCaps.isOnscreen() && !chosenCaps.isBackgroundOpaque()) { + // Set the context opacity + CGL.setContextOpacity(ctx, 0); + } + } finally { + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + pixelFormat = 0; } - backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); - setSwapInterval(1); // enabled per default in layered surface - } - } finally { - if(0!=pixelFormat) { - CGL.deletePixelFormat(pixelFormat); - } - } - return ctx; - } - - @Override - public boolean destroy(long ctx) { - if(0 != nsOpenGLLayer) { - final NativeSurface surface = drawable.getNativeSurface(); - if (DEBUG) { - System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)); - } - final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); - if(null != ols && ols.isSurfaceLayerAttached()) { - // still having a valid OLS attached to surface (parent OLS could have been removed) - ols.detachSurfaceLayer(); } - CGL.releaseNSOpenGLLayer(nsOpenGLLayer); - CGL.deletePixelFormat(nsOpenGLLayerPFmt); - nsOpenGLLayerPFmt = 0; - nsOpenGLLayer = 0; + return ctx; } - return CGL.deleteContext(ctx, true); - } - @Override - public boolean copyImpl(long src, int mask) { - CGL.copyContext(contextHandle, src, mask); - return true; - } - - @Override - public boolean makeCurrent(long ctx) { - final long cglCtx = CGL.getCGLContext(ctx); - if(0 == cglCtx) { - throw new InternalError("Null CGLContext for: "+this); + @Override + public boolean destroy(long ctx) { + lastPBufferHandle = 0; + return CGL.deleteContext(ctx, true); } - int err = CGL.CGLLockContext(cglCtx); - if(CGL.kCGLNoError == err) { - return CGL.makeCurrentContext(ctx); - } else if(DEBUG) { - System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + + @Override + public boolean contextRealized(boolean realized) { + if( realized ) { + if( null != backingLayerHost ) { + // + // handled layered surface + // + final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities(); + final long ctx = MacOSXCGLContext.this.getHandle(); + final int texID; + final long drawableHandle = drawable.getHandle(); + if(drawable instanceof GLFBODrawableImpl) { + final GLFBODrawableImpl fbod = (GLFBODrawableImpl)drawable; + texID = fbod.getTextureBuffer(GL.GL_FRONT).getName(); + fbod.setSwapBufferContext(new GLFBODrawableImpl.SwapBufferContext() { + public void swapBuffers(boolean doubleBuffered) { + MacOSXCGLContext.NSOpenGLImpl.this.swapBuffers(); + } } ) ; + lastPBufferHandle = 0; + } else if( chosenCaps.isPBuffer() && CGL.isNSOpenGLPixelBuffer(drawableHandle) ) { + texID = 0; + lastPBufferHandle = drawableHandle; + } else { + throw new GLException("BackingLayerHost w/ unknown handle (!FBO, !PBuffer): "+drawable); + } + lastWidth = drawable.getWidth(); + lastHeight = drawable.getHeight(); + if(0>=lastWidth || 0>=lastHeight || !drawable.isRealized()) { + throw new GLException("Drawable not realized yet or invalid texture size, texSize "+lastWidth+"x"+lastHeight+", "+drawable); + } + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, lastPBufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight); + if (DEBUG) { + System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+" w/ pbuffer "+toHexString(lastPBufferHandle)+", texID "+texID+", texSize "+lastWidth+"x"+lastHeight+", "+drawable); + } + backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); + setSwapInterval(1); // enabled per default in layered surface + } else { + lastWidth = drawable.getWidth(); + lastHeight = drawable.getHeight(); + } + } else { + if( 0 != nsOpenGLLayer ) { + final NativeSurface surface = drawable.getNativeSurface(); + if (DEBUG) { + System.err.println("NS destroy nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", "+drawable); + } + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + if(null != ols && ols.isSurfaceLayerAttached()) { + // still having a valid OLS attached to surface (parent OLS could have been removed) + ols.detachSurfaceLayer(); + } + CGL.releaseNSOpenGLLayer(nsOpenGLLayer); + nsOpenGLLayer = 0; + } + if(0 != nsOpenGLLayerPFmt) { + CGL.deletePixelFormat(nsOpenGLLayerPFmt); + nsOpenGLLayerPFmt = 0; + } + lastPBufferHandle = 0; + } + backingLayerHost = null; + return true; } - return false; - } - @Override - public boolean release(long ctx) { - try { - gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze - } catch (GLException gle) { - if(DEBUG) { - System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:"); - gle.printStackTrace(); + private final void validatePBufferConfig(long ctx) { + final GLCapabilitiesImmutable chosenCaps = drawable.getChosenGLCapabilities(); + final long drawableHandle = drawable.getHandle(); + if(chosenCaps.isPBuffer() && CGL.isNSOpenGLPixelBuffer(drawableHandle) && lastPBufferHandle != drawableHandle) { + // Must associate the pbuffer with our newly-created context + lastPBufferHandle = drawableHandle; + if(0 != drawableHandle) { + CGL.setContextPBuffer(ctx, drawableHandle); + } + if(DEBUG) { + System.err.println("NS.validateDrawableConfig bind pbuffer "+toHexString(drawableHandle)+" -> ctx "+toHexString(ctx)); + } } } - final boolean res = CGL.clearCurrentContext(ctx); - final long cglCtx = CGL.getCGLContext(ctx); - if(0 == cglCtx) { - throw new InternalError("Null CGLContext for: "+this); + + /** Returns true if size has been updated, otherwise false (same size). */ + private final boolean validateDrawableSizeConfig(long ctx) { + final int width = drawable.getWidth(); + final int height = drawable.getHeight(); + if( lastWidth != width || lastHeight != height ) { + lastWidth = drawable.getWidth(); + lastHeight = drawable.getHeight(); + if(DEBUG) { + System.err.println("NS.validateDrawableConfig size changed"); + } + return true; + } + return false; } - final int err = CGL.CGLUnlockContext(cglCtx); - if(DEBUG && CGL.kCGLNoError != err) { - System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this); + + @Override + public boolean copyImpl(long src, int mask) { + CGL.copyContext(contextHandle, src, mask); + return true; } - return res && CGL.kCGLNoError == err; - } - @Override - public boolean setSwapInterval(int interval) { - if(0 != nsOpenGLLayer) { - CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); - vsyncTimeout = interval * (int)screenVSyncTimeout; - if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); } + @Override + public boolean makeCurrent(long ctx) { + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + int err = CGL.CGLLockContext(cglCtx); + if(CGL.kCGLNoError == err) { + validatePBufferConfig(ctx); // required to handle pbuffer change ASAP + return CGL.makeCurrentContext(ctx); + } else if(DEBUG) { + System.err.println("NSGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return false; } - CGL.setSwapInterval(contextHandle, interval); - return true; - } - @Override - public boolean swapBuffers() { - if( 0 != nsOpenGLLayer ) { - // If v-sync is disabled, frames will be drawn as quickly as possible - // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync). - CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout); + @Override + public boolean release(long ctx) { + try { + gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze + } catch (GLException gle) { + if(DEBUG) { + System.err.println("MacOSXCGLContext.NSOpenGLImpl.release: INFO: glFlush() catched exception:"); + gle.printStackTrace(); + } + } + final boolean res = CGL.clearCurrentContext(ctx); + final long cglCtx = CGL.getCGLContext(ctx); + if(0 == cglCtx) { + throw new InternalError("Null CGLContext for: "+this); + } + final int err = CGL.CGLUnlockContext(cglCtx); + if(DEBUG && CGL.kCGLNoError != err) { + System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err)+": "+this); + } + return res && CGL.kCGLNoError == err; } - if(CGL.flushBuffer(contextHandle)) { + + @Override + public boolean detachPBuffer() { + if(0 != lastPBufferHandle) { + lastPBufferHandle = 0; + if(0 != nsOpenGLLayer) { + CGL.flushNSOpenGLLayerPBuffer(nsOpenGLLayer); // notify invalid pbuffer + } + // CGL.setContextPBuffer(contextHandle, 0); // doesn't work, i.e. not taking nil + } + return true; + } + + @Override + public boolean setSwapInterval(int interval) { if(0 != nsOpenGLLayer) { - // trigger CALayer to update - CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer); + CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); + vsyncTimeout = interval * (int)screenVSyncTimeout + 1000; // +1ms + if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); } } + CGL.setSwapInterval(contextHandle, interval); return true; } - return false; - } + + private int skipSync=0; + + @Override + public boolean swapBuffers() { + final boolean res; + if( 0 != nsOpenGLLayer ) { + if( validateDrawableSizeConfig(contextHandle) ) { + // skip wait-for-vsync for a few frames if size has changed, + // allowing to update the texture IDs ASAP. + skipSync = 10; + } + + final int texID; + final boolean valid; + if(drawable instanceof GLFBODrawableImpl) { + texID = ((GLFBODrawableImpl)drawable).getTextureBuffer(GL.GL_FRONT).getName(); + valid = 0 != texID; + } else { + texID = 0; + valid = 0 != lastPBufferHandle; + } + if(valid) { + if(0 == skipSync) { + // If v-sync is disabled, frames will be drawn as quickly as possible + // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync). + CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout); + } else { + skipSync--; + } + res = CGL.flushBuffer(contextHandle); + if(res) { + // trigger CALayer to update incl. possible surface change + CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer, lastPBufferHandle, texID, lastWidth, lastHeight); + } + } else { + res = true; + } + } else { + res = CGL.flushBuffer(contextHandle); + } + return res; + } + } class CGLImpl implements GLBackendImpl { - @Override - public boolean isNSContext() { return false; } - - @Override - public long create(long share, int ctp, int major, int minor) { - long ctx = 0; - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor); - if (pixelFormat == 0) { - throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); - } - config.setChosenPixelFormat(pixelFormat); - try { - // Create new context - PointerBuffer ctxPB = PointerBuffer.allocateDirect(1); - if (DEBUG) { - System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share)); - } - int res = CGL.CGLCreateContext(pixelFormat, share, ctxPB); - if (res != CGL.kCGLNoError) { - throw new GLException("Error code " + res + " while creating context"); + @Override + public boolean isNSContext() { return false; } + + @Override + public long create(long share, int ctp, int major, int minor) { + long ctx = 0; + MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2CGLPixelFormat(chosenCaps, ctp, major, minor); + if (pixelFormat == 0) { + throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); } - if(chosenCaps.isPBuffer()) { - // Attach newly-created context to the pbuffer - res = CGL.CGLSetPBuffer(ctxPB.get(0), drawable.getHandle(), 0, 0, 0); + try { + // Create new context + PointerBuffer ctxPB = PointerBuffer.allocateDirect(1); + if (DEBUG) { + System.err.println("Share context for CGL-based pbuffer context is " + toHexString(share)); + } + int res = CGL.CGLCreateContext(pixelFormat, share, ctxPB); if (res != CGL.kCGLNoError) { - throw new GLException("Error code " + res + " while attaching context to pbuffer"); + throw new GLException("Error code " + res + " while creating context"); } - } - ctx = ctxPB.get(0); - if(0!=ctx) { - if(DEBUG) { - GLCapabilitiesImmutable caps0 = MacOSXCGLGraphicsConfiguration.CGLPixelFormat2GLCapabilities(pixelFormat); - System.err.println("NS created: "+caps0); + ctx = ctxPB.get(0); + + if (0 != ctx) { + GLCapabilities fixedCaps = MacOSXCGLGraphicsConfiguration.CGLPixelFormat2GLCapabilities(pixelFormat); + fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); + if(chosenCaps.isOnscreen() || !fixedCaps.isPBuffer()) { + // not handled, so copy them + fixedCaps.setFBO(chosenCaps.isFBO()); + fixedCaps.setPBuffer(chosenCaps.isPBuffer()); + fixedCaps.setBitmap(chosenCaps.isBitmap()); + fixedCaps.setOnscreen(chosenCaps.isOnscreen()); + } + config.setChosenCapabilities(fixedCaps); + if(DEBUG) { + System.err.println("CGL create fixedCaps: "+fixedCaps); + } + if(fixedCaps.isPBuffer()) { + // Must now associate the pbuffer with our newly-created context + res = CGL.CGLSetPBuffer(ctx, drawable.getHandle(), 0, 0, 0); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while attaching context to pbuffer"); + } + } } + } finally { + CGL.CGLDestroyPixelFormat(pixelFormat); } - } finally { - CGL.CGLDestroyPixelFormat(pixelFormat); + return ctx; } - return ctx; - } - @Override - public boolean destroy(long ctx) { - return CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError; - } + @Override + public boolean destroy(long ctx) { + return CGL.CGLDestroyContext(ctx) == CGL.kCGLNoError; + } - @Override - public boolean copyImpl(long src, int mask) { - CGL.CGLCopyContext(src, contextHandle, mask); - return true; - } + @Override + public boolean contextRealized(boolean realized) { + return true; + } + + @Override + public boolean copyImpl(long src, int mask) { + CGL.CGLCopyContext(src, contextHandle, mask); + return true; + } - @Override - public boolean makeCurrent(long ctx) { - int err = CGL.CGLLockContext(ctx); - if(CGL.kCGLNoError == err) { - err = CGL.CGLSetCurrentContext(ctx); + @Override + public boolean makeCurrent(long ctx) { + int err = CGL.CGLLockContext(ctx); if(CGL.kCGLNoError == err) { - return true; + err = CGL.CGLSetCurrentContext(ctx); + if(CGL.kCGLNoError == err) { + return true; + } else if(DEBUG) { + System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this); + } } else if(DEBUG) { - System.err.println("CGL: Could not make context current: err 0x"+Integer.toHexString(err)+": "+this); + System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); } - } else if(DEBUG) { - System.err.println("CGL: Could not lock context: err 0x"+Integer.toHexString(err)+": "+this); + return false; } - return false; - } - @Override - public boolean release(long ctx) { - try { - gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze - } catch (GLException gle) { - if(DEBUG) { - System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:"); - gle.printStackTrace(); + @Override + public boolean release(long ctx) { + try { + gl.glFlush(); // w/o glFlush()/glFinish() OSX < 10.7 (NVidia driver) may freeze + } catch (GLException gle) { + if(DEBUG) { + System.err.println("MacOSXCGLContext.CGLImpl.release: INFO: glFlush() catched exception:"); + gle.printStackTrace(); + } } + int err = CGL.CGLSetCurrentContext(0); + if(DEBUG && CGL.kCGLNoError != err) { + System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this); + } + int err2 = CGL.CGLUnlockContext(ctx); + if(DEBUG && CGL.kCGLNoError != err2) { + System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this); + } + return CGL.kCGLNoError == err && CGL.kCGLNoError == err2; + } + + @Override + public boolean detachPBuffer() { + /* Doesn't work, i.e. not taking NULL + final int res = CGL.CGLSetPBuffer(contextHandle, 0, 0, 0, 0); + if (res != CGL.kCGLNoError) { + throw new GLException("Error code " + res + " while detaching context from pbuffer"); + } */ + return true; } - int err = CGL.CGLSetCurrentContext(0); - if(DEBUG && CGL.kCGLNoError != err) { - System.err.println("CGL: Could not release current context: err 0x"+Integer.toHexString(err)+": "+this); + + @Override + public boolean setSwapInterval(int interval) { + int[] lval = new int[] { interval } ; + CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); + return true; } - int err2 = CGL.CGLUnlockContext(ctx); - if(DEBUG && CGL.kCGLNoError != err2) { - System.err.println("CGL: Could not unlock context: err 0x"+Integer.toHexString(err2)+": "+this); + @Override + public boolean swapBuffers() { + return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); } - return CGL.kCGLNoError == err && CGL.kCGLNoError == err2; - } - - @Override - public boolean setSwapInterval(int interval) { - int[] lval = new int[] { interval } ; - CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); - return true; - } - @Override - public boolean swapBuffers() { - return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); - } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java index af767f0c3..cc727c8e1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -42,10 +42,10 @@ package jogamp.opengl.macosx.cgl; import java.lang.ref.WeakReference; import java.util.ArrayList; -import java.util.Iterator; import java.util.List; import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -92,7 +92,7 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { this.id = id; } } - private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); + /* pp */ List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); private boolean haveSetOpenGLMode = false; private GLBackendType openGLMode = GLBackendType.NSOPENGL; @@ -110,26 +110,42 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { return GLBackendType.NSOPENGL == openGLMode ? getHandle() : 0; } - protected void registerContext(MacOSXCGLContext ctx) { + @Override + protected void associateContext(GLContext ctx, boolean bound) { // NOTE: we need to keep track of the created contexts in order to // implement swapBuffers() because of how Mac OS X implements its // OpenGL window interface synchronized (createdContexts) { - createdContexts.add(new WeakReference<MacOSXCGLContext>(ctx)); - } + if(bound) { + createdContexts.add(new WeakReference<MacOSXCGLContext>((MacOSXCGLContext)ctx)); + } else { + for(int i=0; i<createdContexts.size(); ) { + final WeakReference<MacOSXCGLContext> ref = createdContexts.get(i); + final MacOSXCGLContext _ctx = ref.get(); + if( _ctx == null || _ctx == ctx) { + createdContexts.remove(i); + } else { + i++; + } + } + } + } } + @Override - protected final void swapBuffersImpl() { - // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() - synchronized (createdContexts) { - for (Iterator<WeakReference<MacOSXCGLContext>> iter = createdContexts.iterator(); iter.hasNext(); ) { - WeakReference<MacOSXCGLContext> ref = iter.next(); - MacOSXCGLContext ctx = ref.get(); - if (ctx != null) { - ctx.swapBuffers(); - } else { - iter.remove(); - } + protected final void swapBuffersImpl(boolean doubleBuffered) { + if(doubleBuffered) { + synchronized (createdContexts) { + for(int i=0; i<createdContexts.size(); ) { + final WeakReference<MacOSXCGLContext> ref = createdContexts.get(i); + final MacOSXCGLContext ctx = ref.get(); + if (ctx != null) { + ctx.swapBuffers(); + i++; + } else { + createdContexts.remove(i); + } + } } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index c1b15cac5..e174d38f4 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -51,7 +51,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.DefaultGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; @@ -60,9 +60,9 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import javax.media.opengl.GLProfile.ShutdownType; -import jogamp.nativewindow.macosx.OSXUtil; +import jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.macosx.OSXDummyUpstreamSurfaceHook; import jogamp.opengl.DesktopGLDynamicLookupHelper; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -72,7 +72,7 @@ import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.JogampRuntimeException; import com.jogamp.common.util.ReflectionUtil; -import com.jogamp.nativewindow.WrappedSurface; +import com.jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.nativewindow.macosx.MacOSXGraphicsDevice; import com.jogamp.opengl.GLExtensions; @@ -124,7 +124,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { } @Override - protected final void destroy(ShutdownType shutdownType) { + protected final void destroy() { if(null != sharedMap) { sharedMap.clear(); sharedMap = null; @@ -133,10 +133,9 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { /** * Pulling away the native library may cause havoc .. * - if(ShutdownType.COMPLETE == shutdownType && null != macOSXCGLDynamicLookupHelper) { - macOSXCGLDynamicLookupHelper.destroy(); - macOSXCGLDynamicLookupHelper = null; - } */ + macOSXCGLDynamicLookupHelper.destroy(); + */ + macOSXCGLDynamicLookupHelper = null; } @Override @@ -322,9 +321,14 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected GLDrawableImpl createOffscreenDrawableImpl(NativeSurface target) { - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration(); + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(!caps.isPBuffer()) { + // Actual implementation is using PBuffer ... + final GLCapabilities modCaps = (GLCapabilities) caps.cloneMutable(); + modCaps.setPBuffer(true); + modCaps.setBitmap(false); + config.setChosenCapabilities(modCaps); return new MacOSXOffscreenCGLDrawable(this, target); } return new MacOSXPbufferCGLDrawable(this, target); @@ -338,7 +342,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) { + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { final MacOSXGraphicsDevice device; if(createNewDevice) { device = new MacOSXGraphicsDevice(deviceReq.getUnitID()); @@ -350,68 +354,23 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } - return new WrappedSurface(config, 0, width, height, lifecycleHook); + return new WrappedSurface(config, 0, upstreamHook, createNewDevice); } @Override public final ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) { final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps); - return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, + new OSXDummyUpstreamSurfaceHook(width, height)); } - private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() { - long nsWindow = 0; - @Override - public final void create(ProxySurface s) { - if(0 == nsWindow && 0 == s.getSurfaceHandle()) { - nsWindow = OSXUtil.CreateNSWindow(0, 0, s.getWidth(), s.getHeight()); - if(0 == nsWindow) { - throw new GLException("Error NS window 0"); - } - long nsView = OSXUtil.GetNSView(nsWindow); - if(0 == nsView) { - throw new GLException("Error NS view 0"); - } - s.setSurfaceHandle(nsView); - s.setImplBitfield(ProxySurface.INVISIBLE_WINDOW); - if(DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final void destroy(ProxySurface s) { - if(0 != nsWindow && 0 != s.getSurfaceHandle()) { - OSXUtil.DestroyNSWindow(nsWindow); - nsWindow = 0; - s.setSurfaceHandle(0); - if(DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.dummySurfaceLifecycleHook.destroy: "+s); - } - } - } - @Override - public final int getWidth(ProxySurface s) { - return s.initialWidth; - } - @Override - public final int getHeight(ProxySurface s) { - return s.initialHeight; - } - - @Override - public String toString() { - return "MacOSXLSurfaceLifecycleHook[]"; - } - - }; @Override protected ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { final MacOSXGraphicsDevice device = new MacOSXGraphicsDevice(deviceReq.getUnitID()); final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final MacOSXCGLGraphicsConfiguration config = MacOSXCGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen, true); - return new WrappedSurface(config, windowHandle, 0, 0, upstream); + return new WrappedSurface(config, windowHandle, upstream, true); } @Override diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java index 202644bb3..8866c7ce6 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java @@ -51,23 +51,16 @@ import com.jogamp.common.nio.PointerBuffer; import com.jogamp.nativewindow.MutableGraphicsConfiguration; public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { - long pixelformat; MacOSXCGLGraphicsConfiguration(AbstractGraphicsScreen screen, - GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - long pixelformat) { + GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested) { super(screen, capsChosen, capsRequested); - this.pixelformat=pixelformat; } public Object clone() { return super.clone(); } - void setChosenPixelFormat(long pixelformat) { - this.pixelformat=pixelformat; - } - protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(MacOSXCGLDrawableFactory factory, AbstractGraphicsDevice device) { MacOSXCGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateOSXSharedResource(device); if(null == sharedResource) { @@ -114,11 +107,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration break; case CGL.kCGLPFAColorFloat: - ivalues[idx] = caps.getPbufferFloatingPointBuffers() ? 1 : 0; + ivalues[idx] = ( !caps.isOnscreen() && caps.isPBuffer() && caps.getPbufferFloatingPointBuffers() ) ? 1 : 0; break; case CGL.NSOpenGLPFAPixelBuffer: - ivalues[idx] = caps.isPBuffer() ? 1 : 0; + ivalues[idx] = ( !caps.isOnscreen() && caps.isPBuffer() ) ? 1 : 0; break; case CGL.NSOpenGLPFADoubleBuffer: @@ -176,7 +169,7 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration return CGL.createPixelFormat(cglInternalAttributeToken, off, len, ivalues, 0); } - static GLCapabilitiesImmutable NSPixelFormat2GLCapabilities(GLProfile glp, long pixelFormat) { + static GLCapabilities NSPixelFormat2GLCapabilities(GLProfile glp, long pixelFormat) { return PixelFormat2GLCapabilities(glp, pixelFormat, true); } @@ -188,11 +181,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration attrs[i++] = CGL.kCGLPFAOpenGLProfile; attrs[i++] = MacOSXCGLContext.GLProfile2CGLOGLProfileValue(ctp, major, minor); } - if(caps.isPBuffer()) { + if(!caps.isOnscreen() && caps.isPBuffer()) { attrs[i++] = CGL.kCGLPFAPBuffer; - } - if (caps.getPbufferFloatingPointBuffers()) { - attrs[i++] = CGL.kCGLPFAColorFloat; + if (caps.getPbufferFloatingPointBuffers()) { + attrs[i++] = CGL.kCGLPFAColorFloat; + } } if (caps.getDoubleBuffered()) { attrs[i++] = CGL.kCGLPFADoubleBuffer; @@ -233,11 +226,11 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration return fmt.get(0); } - static GLCapabilitiesImmutable CGLPixelFormat2GLCapabilities(long pixelFormat) { + static GLCapabilities CGLPixelFormat2GLCapabilities(long pixelFormat) { return PixelFormat2GLCapabilities(null, pixelFormat, false); } - private static GLCapabilitiesImmutable PixelFormat2GLCapabilities(GLProfile glp, long pixelFormat, boolean nsUsage) { + private static GLCapabilities PixelFormat2GLCapabilities(GLProfile glp, long pixelFormat, boolean nsUsage) { int len = cglInternalAttributeToken.length; int off = 0; if ( !MacOSXCGLContext.isLionOrLater ) { @@ -280,7 +273,7 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration if(null == glp) { glp = GLProfile.get(GLProfile.GL2); } - GLCapabilities caps = new GLCapabilities(glp); + final GLCapabilities caps = new GLCapabilities(glp); int alphaBits = 0; for (int i = 0; i < len; i++) { int attr = cglInternalAttributeToken[i+off]; @@ -353,7 +346,7 @@ public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration } } caps.setAlphaBits(alphaBits); - + return caps; } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java index f138e7557..43a9d0d1a 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfigurationFactory.java @@ -34,13 +34,19 @@ package jogamp.opengl.macosx.cgl; import jogamp.opengl.GLGraphicsConfigurationFactory; +import jogamp.opengl.GLGraphicsConfigurationUtil; +import jogamp.opengl.x11.glx.X11GLXDrawableFactory; + import javax.media.nativewindow.AbstractGraphicsConfiguration; +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; /** Subclass of GraphicsConfigurationFactory used when non-AWT tookits @@ -58,13 +64,7 @@ public class MacOSXCGLGraphicsConfigurationFactory extends GLGraphicsConfigurati protected AbstractGraphicsConfiguration chooseGraphicsConfigurationImpl( CapabilitiesImmutable capsChosen, CapabilitiesImmutable capsRequested, CapabilitiesChooser chooser, AbstractGraphicsScreen absScreen, int nativeVisualID) { - return chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, absScreen, false); - } - - static MacOSXCGLGraphicsConfiguration chooseGraphicsConfigurationStatic(CapabilitiesImmutable capsChosen, - CapabilitiesImmutable capsRequested, - CapabilitiesChooser chooser, - AbstractGraphicsScreen absScreen, boolean usePBuffer) { + if (absScreen == null) { throw new IllegalArgumentException("AbstractGraphicsScreen is null"); } @@ -77,11 +77,25 @@ public class MacOSXCGLGraphicsConfigurationFactory extends GLGraphicsConfigurati throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - requested"); } - if (chooser != null && - !(chooser instanceof GLCapabilitiesChooser)) { + if (chooser != null && !(chooser instanceof GLCapabilitiesChooser)) { throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilitiesChooser objects"); } + + return chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, (GLCapabilitiesChooser)chooser, absScreen, false); + } + + static MacOSXCGLGraphicsConfiguration chooseGraphicsConfigurationStatic(GLCapabilitiesImmutable capsChosen, + GLCapabilitiesImmutable capsRequested, + GLCapabilitiesChooser chooser, + AbstractGraphicsScreen absScreen, boolean usePBuffer) { + if (absScreen == null) { + throw new IllegalArgumentException("AbstractGraphicsScreen is null"); + } + final MacOSXCGLDrawableFactory factory = (MacOSXCGLDrawableFactory) GLDrawableFactory.getDesktopFactory(); + final AbstractGraphicsDevice device = absScreen.getDevice(); - return new MacOSXCGLGraphicsConfiguration(absScreen, (GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, 0); + capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLContext.isFBOAvailable(device, capsChosen.getGLProfile()), factory.canCreateGLPbuffer(device) ); + + return new MacOSXCGLGraphicsConfiguration(absScreen, (GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested); } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java index 6be9e386d..65ed5fc15 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java @@ -49,8 +49,8 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; -import com.jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLContextShareSet; import jogamp.opengl.macosx.cgl.MacOSXCGLDrawable.GLBackendType; @@ -62,7 +62,6 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { private MacOSXExternalCGLContext(Drawable drawable, boolean isNSContext, long handle) { super(drawable, null); setOpenGLMode(isNSContext ? GLBackendType.NSOPENGL : GLBackendType.CGL ); - drawable.registerContext(this); this.contextHandle = handle; GLContextShareSet.contextCreated(this); setGLFunctionAvailability(false, 0, 0, CTX_PROFILE_COMPAT); @@ -108,13 +107,13 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { } AbstractGraphicsScreen aScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_MACOSX); - MacOSXCGLGraphicsConfiguration cfg = new MacOSXCGLGraphicsConfiguration(aScreen, caps, caps, pixelFormat); + MacOSXCGLGraphicsConfiguration cfg = new MacOSXCGLGraphicsConfiguration(aScreen, caps, caps); if(0 == currentDrawable) { // set a fake marker stating a valid drawable currentDrawable = 1; } - WrappedSurface ns = new WrappedSurface(cfg, currentDrawable, 64, 64, null); + WrappedSurface ns = new WrappedSurface(cfg, currentDrawable, 64, 64, true); return new MacOSXExternalCGLContext(new Drawable(factory, ns), isNSContext, contextHandle); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java index b1e283ebc..ec9628004 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java @@ -52,9 +52,7 @@ public class MacOSXOnscreenCGLDrawable extends MacOSXCGLDrawable { @Override public GLContext createContext(GLContext shareWith) { - final MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); - registerContext(ctx); - return ctx; + return new MacOSXOnscreenCGLContext(this, shareWith); } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java index 88886ddd2..7e2d8cf10 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java @@ -39,6 +39,7 @@ import javax.media.opengl.GLPbuffer; import jogamp.opengl.GLContextImpl; +@SuppressWarnings("deprecation") public class MacOSXPbufferCGLContext extends MacOSXCGLContext { // State for render-to-texture and render-to-texture-rectangle support diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java index 8f2f386af..668e463a2 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java @@ -40,6 +40,8 @@ package jogamp.opengl.macosx.cgl; +import java.lang.ref.WeakReference; + import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.MutableSurface; @@ -70,9 +72,6 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV // private int texture; // actual texture object - // Note that we can not store this in the NativeSurface because the - // semantic is that contains an NSView - protected long pBuffer; protected int pBufferTexTarget, pBufferTexWidth, pBufferTexHeight; public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target) { @@ -90,9 +89,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { @Override public GLContext createContext(GLContext shareWith) { - final MacOSXPbufferCGLContext ctx = new MacOSXPbufferCGLContext(this, shareWith); - registerContext(ctx); - return ctx; + return new MacOSXPbufferCGLContext(this, shareWith); } @Override @@ -101,27 +98,34 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { return 0; } - @Override - public long getHandle() { - return pBuffer; - } - protected int getTextureTarget() { return pBufferTexTarget; } protected int getTextureWidth() { return pBufferTexWidth; } protected int getTextureHeight() { return pBufferTexHeight; } protected void destroyPbuffer() { - if (this.pBuffer != 0) { - NativeSurface ns = getNativeSurface(); + final MutableSurface ms = (MutableSurface) getNativeSurface(); + final long pBuffer = ms.getSurfaceHandle(); + if (0 != pBuffer) { + synchronized (createdContexts) { + for(int i=0; i<createdContexts.size(); ) { + final WeakReference<MacOSXCGLContext> ref = createdContexts.get(i); + final MacOSXCGLContext ctx = ref.get(); + if (ctx != null) { + ctx.detachPBuffer(); + i++; + } else { + createdContexts.remove(i); + } + } + } impl.destroy(pBuffer); - this.pBuffer = 0; - ((MutableSurface)ns).setSurfaceHandle(0); + ms.setSurfaceHandle(0); } } private void createPbuffer() { - final NativeSurface ns = getNativeSurface(); - final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration(); + final MutableSurface ms = (MutableSurface) getNativeSurface(); + final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ms.getGraphicsConfiguration(); final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); final GLProfile glProfile = capabilities.getGLProfile(); MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory)factory).getOrCreateOSXSharedResource(config.getScreen().getDevice()); @@ -161,7 +165,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { } } - pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); + final long pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); if(DEBUG) { System.err.println("MacOSXPbufferCGLDrawable tex: target "+toHexString(pBufferTexTarget)+ ", pbufferSize "+getWidth()+"x"+getHeight()+ @@ -174,7 +178,7 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { throw new GLException("pbuffer creation error: CGL.createPBuffer() failed"); } - ((MutableSurface)ns).setSurfaceHandle(pBuffer); + ms.setSurfaceHandle(pBuffer); } @Override diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java index 96c1187d3..f6cc2956d 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLContext.java @@ -50,8 +50,8 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import com.jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.WrappedSurface; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLContextShareSet; @@ -102,7 +102,7 @@ public class WindowsExternalWGLContext extends WindowsWGLContext { System.err.println("WindowsExternalWGLContext valid hdc/pfd, retrieved cfg: " + cfg); } } - return new WindowsExternalWGLContext(new Drawable(factory, new WrappedSurface(cfg, hdc, 64, 64, null)), ctx, cfg); + return new WindowsExternalWGLContext(new Drawable(factory, new WrappedSurface(cfg, hdc, 64, 64, true)), ctx, cfg); } @Override diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java index 15bd005dc..f8c237c9e 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsExternalWGLDrawable.java @@ -49,10 +49,10 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.WrappedSurface; import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.GDIUtil; -import com.jogamp.nativewindow.WrappedSurface; public class WindowsExternalWGLDrawable extends WindowsWGLDrawable { @@ -72,7 +72,7 @@ public class WindowsExternalWGLDrawable extends WindowsWGLDrawable { final AbstractGraphicsScreen aScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS); final WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfiguration.createFromExternal(factory, hdc, pfdID, glp, aScreen, true); - return new WindowsExternalWGLDrawable(factory, new WrappedSurface(cfg, hdc, 64, 64, null)); + return new WindowsExternalWGLDrawable(factory, new WrappedSurface(cfg, hdc, 64, 64, true)); } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java index 175622343..75c1c4441 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java @@ -40,6 +40,7 @@ package jogamp.opengl.windows.wgl; +import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.MutableSurface; @@ -52,6 +53,7 @@ import javax.media.opengl.GLProfile; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory.SharedResource; // import javax.media.opengl.GLPbuffer; @@ -127,13 +129,16 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { System.out.println("Pbuffer config: " + config); } + final int winattrPbuffer = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(false /* onscreen */, false /* fbo */, true /* pbuffer */, false /* bitmap */); + int[] iattributes = new int [2*WindowsWGLGraphicsConfiguration.MAX_ATTRIBS]; float[] fattributes = new float[1]; int[] floatModeTmp = new int[1]; int niattribs = 0; - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GLProfile glProfile = chosenCaps.getGLProfile(); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + final GLProfile glProfile = chosenCaps.getGLProfile(); + final AbstractGraphicsDevice device = config.getScreen().getDevice(); if (DEBUG) { System.out.println("Pbuffer parentHdc = " + toHexString(sharedHdc)); @@ -175,7 +180,8 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { if (DEBUG) { System.err.println("" + nformats + " suitable pixel formats found"); for (int i = 0; i < nformats; i++) { - WGLGLCapabilities dbgCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, sharedHdc, pformats[i], glProfile, false, true); + WGLGLCapabilities dbgCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, device, glProfile, + sharedHdc, pformats[i], winattrPbuffer); System.err.println("pixel format " + pformats[i] + " (index " + i + "): " + dbgCaps); } } @@ -239,7 +245,8 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { // Re-query chosen pixel format { - WGLGLCapabilities newCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, sharedHdc, pfdid, glProfile, false, true); + WGLGLCapabilities newCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, device, glProfile, + sharedHdc, pfdid, winattrPbuffer); if(null == newCaps) { throw new GLException("pbuffer creation error: unable to re-query chosen PFD ID: " + pfdid + ", hdc " + GLDrawableImpl.toHexString(tmpHdc)); } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java index ca7886e7f..3b3f0c123 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java @@ -73,27 +73,28 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl { } @Override - protected final void swapBuffersImpl() { - // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() - final long t0; - if (PROFILING) { - t0 = System.currentTimeMillis(); - } else { - t0 = 0; - } - - if (!WGLUtil.SwapBuffers(getHandle()) && (GDI.GetLastError() != GDI.ERROR_SUCCESS)) { - throw new GLException("Error swapping buffers"); - } - - if (PROFILING) { - profilingSwapBuffersTime += System.currentTimeMillis() - t0; - if (++profilingSwapBuffersTicks == PROFILING_TICKS) { - System.err.println("SwapBuffers calls: " + profilingSwapBuffersTime + " ms / " + PROFILING_TICKS + " calls (" + - ((float) profilingSwapBuffersTime / (float) PROFILING_TICKS) + " ms/call)"); - profilingSwapBuffersTime = 0; - profilingSwapBuffersTicks = 0; - } + protected final void swapBuffersImpl(boolean doubleBuffered) { + if(doubleBuffered) { + final long t0; + if (PROFILING) { + t0 = System.currentTimeMillis(); + } else { + t0 = 0; + } + + if (!WGLUtil.SwapBuffers(getHandle()) && (GDI.GetLastError() != GDI.ERROR_SUCCESS)) { + throw new GLException("Error swapping buffers"); + } + + if (PROFILING) { + profilingSwapBuffersTime += System.currentTimeMillis() - t0; + if (++profilingSwapBuffersTicks == PROFILING_TICKS) { + System.err.println("SwapBuffers calls: " + profilingSwapBuffersTime + " ms / " + PROFILING_TICKS + " calls (" + + ((float) profilingSwapBuffersTime / (float) PROFILING_TICKS) + " ms/call)"); + profilingSwapBuffersTime = 0; + profilingSwapBuffersTicks = 0; + } + } } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index c414083c4..91d5c225a 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -52,7 +52,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.DefaultGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; @@ -61,11 +61,11 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import javax.media.opengl.GLProfile.ShutdownType; +import jogamp.nativewindow.WrappedSurface; import jogamp.nativewindow.windows.GDI; +import jogamp.nativewindow.windows.GDIDummyUpstreamSurfaceHook; import jogamp.nativewindow.windows.GDISurface; -import jogamp.nativewindow.windows.GDIUtil; import jogamp.nativewindow.windows.RegisteredClassFactory; import jogamp.opengl.DesktopGLDynamicLookupHelper; import jogamp.opengl.GLContextImpl; @@ -80,7 +80,6 @@ import com.jogamp.common.nio.PointerBuffer; import com.jogamp.common.os.Platform; import com.jogamp.common.util.ReflectionUtil; import com.jogamp.common.util.VersionNumber; -import com.jogamp.nativewindow.WrappedSurface; import com.jogamp.nativewindow.windows.WindowsGraphicsDevice; import com.jogamp.opengl.GLExtensions; @@ -136,7 +135,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { @Override - protected final void destroy(ShutdownType shutdownType) { + protected final void destroy() { if(null != sharedResourceRunner) { sharedResourceRunner.stop(); sharedResourceRunner = null; @@ -149,10 +148,9 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { /** * Pulling away the native library may cause havoc .. * - if(ShutdownType.COMPLETE == shutdownType && null != windowsWGLDynamicLookupHelper) { - windowsWGLDynamicLookupHelper.destroy(); - windowsWGLDynamicLookupHelper = null; - } */ + windowsWGLDynamicLookupHelper.destroy(); + */ + windowsWGLDynamicLookupHelper = null; RegisteredClassFactory.shutdownSharedClasses(); } @@ -543,7 +541,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { @Override protected final ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) { + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { final WindowsGraphicsDevice device; if(createNewDevice) { device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID()); @@ -555,7 +553,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } - return new WrappedSurface(config, 0, width, height, lifecycleHook); + return new WrappedSurface(config, 0, upstreamHook, createNewDevice); } @Override @@ -573,57 +571,15 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+requestedCaps+" on "+screen); } - return new GDISurface(config, 0, width, height, dummySurfaceLifecycleHook); - } - private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() { - @Override - public final void create(ProxySurface s) { - final GDISurface ms = (GDISurface)s; - if(0 == ms.getWindowHandle()) { - final long windowHandle = GDIUtil.CreateDummyWindow(0, 0, s.getWidth(), s.getHeight()); - if(0 == windowHandle) { - throw new GLException("Error windowHandle 0, werr: "+GDI.GetLastError()); - } - ms.setWindowHandle(windowHandle); - if(DEBUG) { - System.err.println("WindowsWGLDrawableFactory.dummySurfaceLifecycleHook.create: "+ms); - } - } - } - @Override - public final void destroy(ProxySurface s) { - final GDISurface ms = (GDISurface)s; - if(0 != ms.getWindowHandle()) { - GDI.ShowWindow(ms.getWindowHandle(), GDI.SW_HIDE); - GDIUtil.DestroyDummyWindow(ms.getWindowHandle()); - ms.setWindowHandle(0); - if(DEBUG) { - System.err.println("WindowsWGLDrawableFactory.dummySurfaceLifecycleHook.destroy: "+ms); - } - } - } - @Override - public final int getWidth(ProxySurface s) { - return s.initialWidth; - } - @Override - public final int getHeight(ProxySurface s) { - return s.initialHeight; - } - - @Override - public String toString() { - return "GDISurfaceLifecycleHook[]"; - } - }; - + return new GDISurface(config, 0, new GDIDummyUpstreamSurfaceHook(width, height), createNewDevice); + } @Override protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { final WindowsGraphicsDevice device = new WindowsGraphicsDevice(deviceReq.getConnection(), deviceReq.getUnitID()); final AbstractGraphicsScreen screen = new DefaultGraphicsScreen(device, screenIdx); final WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsRequested, capsRequested, chooser, screen); - return new GDISurface(cfg, windowHandle, 0, 0, upstream); + return new GDISurface(cfg, windowHandle, upstream, true); } @Override diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java index 209589b29..058f4e336 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -57,6 +57,7 @@ import jogamp.nativewindow.windows.PIXELFORMATDESCRIPTOR; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLGraphicsConfigurationUtil; +@SuppressWarnings("deprecation") public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { protected static final int MAX_PFORMATS = 256; protected static final int MAX_ATTRIBS = 256; @@ -104,9 +105,9 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio WGLGLCapabilities caps = null; if(hasARB) { - caps = wglARBPFID2GLCapabilities(sharedResource, hdc, pfdID, glp, onscreen, true /* pbuffer */); + caps = wglARBPFID2GLCapabilities(sharedResource, device, glp, hdc, pfdID, GLGraphicsConfigurationUtil.ALL_BITS); } else { - caps = PFD2GLCapabilities(glp, hdc, pfdID, onscreen); + caps = PFD2GLCapabilities(device, glp, hdc, pfdID, GLGraphicsConfigurationUtil.ALL_BITS); } if(null==caps) { throw new GLException("Couldn't choose Capabilities by: HDC 0x"+Long.toHexString(hdc)+ @@ -185,7 +186,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio } } if (DEBUG) { - System.err.println("setPixelFormat (ARB): hdc "+toHexString(hdc) +", "+caps); + System.err.println("setPixelFormat: hdc "+toHexString(hdc) +", "+caps); } setCapsPFD(caps); } @@ -273,39 +274,44 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio return true; } - static int[] wglAllARBPFIDs(WindowsWGLContext sharedCtx, long hdc) { + static int wglARBPFDIDCount(WindowsWGLContext sharedCtx, long hdc) { int[] iattributes = new int[1]; int[] iresults = new int[1]; WGLExt wglExt = sharedCtx.getWGLExt(); - iattributes[0] = WGLExt.WGL_NUMBER_PIXEL_FORMATS_ARB; - if (!wglExt.wglGetPixelFormatAttribivARB(hdc, 0, 0, 1, iattributes, 0, iresults, 0)) { + iattributes[0] = WGLExt.WGL_NUMBER_PIXEL_FORMATS_ARB; + // pfdID shall be ignored here (spec), however, pass a valid pdf index '1' below (possible driver bug) + if (!wglExt.wglGetPixelFormatAttribivARB(hdc, 1 /* pfdID */, 0, 1, iattributes, 0, iresults, 0)) { if(DEBUG) { System.err.println("GetPixelFormatAttribivARB: Failed - HDC 0x" + Long.toHexString(hdc) + + ", value "+iresults[0]+ ", LastError: " + GDI.GetLastError()); Thread.dumpStack(); } - return null; + return 0; } - int numFormats = iresults[0]; - if(0 == numFormats) { + final int pfdIDCount = iresults[0]; + if(0 == pfdIDCount) { if(DEBUG) { System.err.println("GetPixelFormatAttribivARB: No formats - HDC 0x" + Long.toHexString(hdc) + ", LastError: " + GDI.GetLastError()); Thread.dumpStack(); } - return null; } - int[] pfdIDs = new int[numFormats]; - for (int i = 0; i < numFormats; i++) { + return pfdIDCount; + } + + static int[] wglAllARBPFDIDs(int pfdIDCount) { + int[] pfdIDs = new int[pfdIDCount]; + for (int i = 0; i < pfdIDCount; i++) { pfdIDs[i] = 1 + i; } return pfdIDs; } - + static WGLGLCapabilities wglARBPFID2GLCapabilities(WindowsWGLDrawableFactory.SharedResource sharedResource, - long hdc, int pfdID, - GLProfile glp, boolean onscreen, boolean usePBuffer) { + AbstractGraphicsDevice device, GLProfile glp, + long hdc, int pfdID, int winattrbits) { if (!sharedResource.hasARBPixelFormat()) { return null; } @@ -319,17 +325,12 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio throw new GLException("wglARBPFID2GLCapabilities: Error getting pixel format attributes for pixel format " + pfdID + " of device context " + toHexString(hdc) + ", werr " + GDI.GetLastError()); } - List<GLCapabilitiesImmutable> bucket = new ArrayList<GLCapabilitiesImmutable>(1); - final int winattrbits = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, false); - if(AttribList2GLCapabilities(bucket, glp, hdc, pfdID, iattributes, niattribs, iresults, winattrbits)) { - return (WGLGLCapabilities) bucket.get(0); - } - return null; + return AttribList2GLCapabilities(device, glp, hdc, pfdID, iattributes, niattribs, iresults, winattrbits); } - static int[] wglChoosePixelFormatARB(long hdc, WindowsWGLDrawableFactory.SharedResource sharedResource, + static int[] wglChoosePixelFormatARB(WindowsWGLDrawableFactory.SharedResource sharedResource, AbstractGraphicsDevice device, GLCapabilitiesImmutable capabilities, - int[] iattributes, int accelerationMode, float[] fattributes) + long hdc, int[] iattributes, int accelerationMode, float[] fattributes) { if ( !WindowsWGLGraphicsConfiguration.GLCapabilities2AttribList(capabilities, @@ -366,27 +367,15 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio + Integer.toHexString(accelerationMode) + ": " + numFormats); for (int i = 0; i < numFormats; i++) { WGLGLCapabilities dbgCaps0 = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities( - sharedResource, hdc, pformats[i], - capabilities.getGLProfile(), capabilities.isOnscreen(), capabilities.isPBuffer()); + sharedResource, device, capabilities.getGLProfile(), hdc, pformats[i], GLGraphicsConfigurationUtil.ALL_BITS); System.err.println("pixel format " + pformats[i] + " (index " + i + "): " + dbgCaps0); } } return pformats; } - static List<GLCapabilitiesImmutable> wglARBPFIDs2GLCapabilities(WindowsWGLDrawableFactory.SharedResource sharedResource, - long hdc, int[] pfdIDs, GLProfile glp, boolean onscreen, boolean usePBuffer) { - final int winattrbits = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, false); - return wglARBPFIDs2GLCapabilitiesImpl(sharedResource, hdc, pfdIDs, glp, winattrbits); - } - - static List <GLCapabilitiesImmutable> wglARBPFIDs2AllGLCapabilities(WindowsWGLDrawableFactory.SharedResource sharedResource, - long hdc, int[] pfdIDs, GLProfile glp) { - return wglARBPFIDs2GLCapabilitiesImpl(sharedResource, hdc, pfdIDs, glp, GLGraphicsConfigurationUtil.ALL_BITS); - } - - private static List <GLCapabilitiesImmutable> wglARBPFIDs2GLCapabilitiesImpl(WindowsWGLDrawableFactory.SharedResource sharedResource, - long hdc, int[] pfdIDs, GLProfile glp, int winattrbits) { + static List <GLCapabilitiesImmutable> wglARBPFIDs2GLCapabilities(WindowsWGLDrawableFactory.SharedResource sharedResource, + AbstractGraphicsDevice device, GLProfile glp, long hdc, int[] pfdIDs, int winattrbits) { if (!sharedResource.hasARBPixelFormat()) { return null; } @@ -401,11 +390,24 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio for(int i = 0; i<numFormats; i++) { if ( pfdIDs[i] >= 1 && ((WindowsWGLContext)sharedResource.getContext()).getWGLExt().wglGetPixelFormatAttribivARB(hdc, pfdIDs[i], 0, niattribs, iattributes, 0, iresults, 0) ) { - AttribList2GLCapabilities(bucket, glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, winattrbits); + final GLCapabilitiesImmutable caps = AttribList2GLCapabilities(device, glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, winattrbits); + if(null != caps) { + bucket.add(caps); + if(DEBUG) { + final int j = bucket.size() - 1; + System.err.println("wglARBPFIDs2GLCapabilities: bucket["+i+" -> "+j+"]: "+caps); + } + } else if(DEBUG) { + GLCapabilitiesImmutable skipped = AttribList2GLCapabilities(device, glp, hdc, pfdIDs[i], iattributes, niattribs, iresults, GLGraphicsConfigurationUtil.ALL_BITS); + System.err.println("wglARBPFIDs2GLCapabilities: bucket["+i+" -> skip]: pfdID "+pfdIDs[i]+", "+skipped+", winattr "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrbits).toString()); + } } else if (DEBUG) { - System.err.println("wglARBPFIDs2GLCapabilities: Cannot get pixel format attributes for pixel format " + - i + "/" + numFormats + ": " + pfdIDs[i] + ", " + - GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrbits).toString()); + if( 1 > pfdIDs[i] ) { + System.err.println("wglARBPFIDs2GLCapabilities: Invalid pfdID " + i + "/" + numFormats + ": " + pfdIDs[i]); + } else { + System.err.println("wglARBPFIDs2GLCapabilities: Cannot get pixel format attributes for pixel format " + + i + "/" + numFormats + ": " + pfdIDs[i] + ", hdc " + toHexString(hdc)); + } } } return bucket; @@ -420,9 +422,6 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio return false; } - boolean onscreen = caps.isOnscreen(); - boolean pbuffer = caps.isPBuffer(); - int niattribs = 0; iattributes[niattribs++] = WGLExt.WGL_SUPPORT_OPENGL_ARB; @@ -431,17 +430,24 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio iattributes[niattribs++] = WGLExt.WGL_ACCELERATION_ARB; iattributes[niattribs++] = accelerationValue; } - if (onscreen) { - iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_WINDOW_ARB; - iattributes[niattribs++] = GL.GL_TRUE; - } else if (pbuffer && sharedResource.hasARBPBuffer()) { - iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_PBUFFER_ARB; - iattributes[niattribs++] = GL.GL_TRUE; + + final boolean usePBuffer = caps.isPBuffer() && sharedResource.hasARBPBuffer() ; + + final int surfaceType; + if( caps.isOnscreen() ) { + surfaceType = WGLExt.WGL_DRAW_TO_WINDOW_ARB; + } else if( caps.isFBO() ) { + surfaceType = WGLExt.WGL_DRAW_TO_WINDOW_ARB; // native replacement! + } else if( usePBuffer ) { + surfaceType = WGLExt.WGL_DRAW_TO_PBUFFER_ARB; + } else if( caps.isBitmap() ) { + surfaceType = WGLExt.WGL_DRAW_TO_BITMAP_ARB; } else { - iattributes[niattribs++] = WGLExt.WGL_DRAW_TO_BITMAP_ARB; - iattributes[niattribs++] = GL.GL_TRUE; + throw new GLException("no surface type set in caps: "+caps); } - + iattributes[niattribs++] = surfaceType; + iattributes[niattribs++] = GL.GL_TRUE; + iattributes[niattribs++] = WGLExt.WGL_DOUBLE_BUFFER_ARB; if (caps.getDoubleBuffered()) { iattributes[niattribs++] = GL.GL_TRUE; @@ -503,7 +509,7 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio boolean useFloat = caps.getPbufferFloatingPointBuffers(); boolean ati = false; boolean nvidia = false; - if (pbuffer && sharedResource.hasARBPBuffer()) { + if ( usePBuffer ) { // Check some invariants and set up some state if (rect && !rtt) { throw new GLException("Render-to-texture-rectangle requires render-to-texture to be specified"); @@ -582,50 +588,56 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio return true; } - static int AttribList2DrawableTypeBits(final int[] iattribs, final int niattribs, final int[] iresults) { + static int AttribList2DrawableTypeBits(final int[] iattribs, + final int niattribs, final int[] iresults) { int val = 0; for (int i = 0; i < niattribs; i++) { int attr = iattribs[i]; switch (attr) { case WGLExt.WGL_DRAW_TO_WINDOW_ARB: - if(iresults[i] == GL.GL_TRUE) val |= GLGraphicsConfigurationUtil.WINDOW_BIT; + if(iresults[i] == GL.GL_TRUE) { + val |= GLGraphicsConfigurationUtil.WINDOW_BIT | + GLGraphicsConfigurationUtil.FBO_BIT; + } break; case WGLExt.WGL_DRAW_TO_BITMAP_ARB: - if(iresults[i] == GL.GL_TRUE) val |= GLGraphicsConfigurationUtil.BITMAP_BIT; + if(iresults[i] == GL.GL_TRUE) { + val |= GLGraphicsConfigurationUtil.BITMAP_BIT; + } break; case WGLExt.WGL_DRAW_TO_PBUFFER_ARB: - if(iresults[i] == GL.GL_TRUE) val |= GLGraphicsConfigurationUtil.PBUFFER_BIT; + if(iresults[i] == GL.GL_TRUE) { + val |= GLGraphicsConfigurationUtil.PBUFFER_BIT; + } break; } } return val; } - static boolean AttribList2GLCapabilities( List<GLCapabilitiesImmutable> capsBucket, - final GLProfile glp, final long hdc, final int pfdID, final int[] iattribs, - final int niattribs, - final int[] iresults, final int winattrmask) { + static WGLGLCapabilities AttribList2GLCapabilities(final AbstractGraphicsDevice device, + final GLProfile glp, final long hdc, final int pfdID, + final int[] iattribs, final int niattribs, final int[] iresults, final int winattrmask) { final int allDrawableTypeBits = AttribList2DrawableTypeBits(iattribs, niattribs, iresults); int drawableTypeBits = winattrmask & allDrawableTypeBits; if( 0 == drawableTypeBits ) { - return false; + return null; } PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(); if (WGLUtil.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { // remove displayable bits, since pfdID is non displayable - drawableTypeBits = drawableTypeBits & ~(GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.BITMAP_BIT); + drawableTypeBits = drawableTypeBits & ~(GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.BITMAP_BIT | GLGraphicsConfigurationUtil.FBO_BIT ); if( 0 == drawableTypeBits ) { - return false; + return null; } // non displayable requested (pbuffer) } - WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp); + final WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp); res.setValuesByARB(iattribs, niattribs, iresults); - - return GLGraphicsConfigurationUtil.addGLCapabilitiesPermutations(capsBucket, res, drawableTypeBits ); + return (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res); } // @@ -651,7 +663,8 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio int dwFlags = pfd.getDwFlags(); if( 0 != (GDI.PFD_DRAW_TO_WINDOW & dwFlags ) ) { - val |= GLGraphicsConfigurationUtil.WINDOW_BIT; + val |= GLGraphicsConfigurationUtil.WINDOW_BIT | + GLGraphicsConfigurationUtil.FBO_BIT; } if( 0 != (GDI.PFD_DRAW_TO_BITMAP & dwFlags ) ) { val |= GLGraphicsConfigurationUtil.BITMAP_BIT; @@ -659,107 +672,124 @@ public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguratio return val; } - static WGLGLCapabilities PFD2GLCapabilities(GLProfile glp, long hdc, int pfdID, boolean onscreen) { - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, false, false); - List<GLCapabilitiesImmutable> capsBucket = new ArrayList<GLCapabilitiesImmutable>(1); - if( PFD2GLCapabilities(capsBucket, glp, hdc, pfdID, winattrmask) ) { - return (WGLGLCapabilities) capsBucket.get(0); - } - return null; - } - - static boolean PFD2GLCapabilities(List<GLCapabilitiesImmutable> capsBucket, final GLProfile glp, final long hdc, final int pfdID, final int winattrmask) { + static WGLGLCapabilities PFD2GLCapabilities(AbstractGraphicsDevice device, final GLProfile glp, final long hdc, final int pfdID, final int winattrmask) { PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(hdc, pfdID); if(null == pfd) { - return false; + return null; } if ((pfd.getDwFlags() & GDI.PFD_SUPPORT_OPENGL) == 0) { - return false; + return null; } final int allDrawableTypeBits = PFD2DrawableTypeBits(pfd); final int drawableTypeBits = winattrmask & allDrawableTypeBits; if( 0 == drawableTypeBits ) { - return false; + return null; } - WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp); + final WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp); res.setValuesByGDI(); + return (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res); + } - return GLGraphicsConfigurationUtil.addGLCapabilitiesPermutations(capsBucket, res, drawableTypeBits ); - } - - static PIXELFORMATDESCRIPTOR GLCapabilities2PFD(GLCapabilitiesImmutable caps, PIXELFORMATDESCRIPTOR pfd) { - int colorDepth = (caps.getRedBits() + - caps.getGreenBits() + - caps.getBlueBits()); - if (colorDepth < 15) { - throw new GLException("Bit depths < 15 (i.e., non-true-color) not supported"); - } - int pfdFlags = (GDI.PFD_SUPPORT_OPENGL | - GDI.PFD_GENERIC_ACCELERATED); - if (caps.getDoubleBuffered()) { - pfdFlags |= GDI.PFD_DOUBLEBUFFER; - } - if (caps.isOnscreen()) { - pfdFlags |= GDI.PFD_DRAW_TO_WINDOW; - } else { - pfdFlags |= GDI.PFD_DRAW_TO_BITMAP; - } - if (caps.getStereo()) { - pfdFlags |= GDI.PFD_STEREO; - } - pfd.setDwFlags(pfdFlags); - pfd.setIPixelType((byte) GDI.PFD_TYPE_RGBA); - pfd.setCColorBits((byte) colorDepth); - pfd.setCRedBits ((byte) caps.getRedBits()); - pfd.setCGreenBits((byte) caps.getGreenBits()); - pfd.setCBlueBits ((byte) caps.getBlueBits()); - pfd.setCAlphaBits((byte) caps.getAlphaBits()); - int accumDepth = (caps.getAccumRedBits() + - caps.getAccumGreenBits() + - caps.getAccumBlueBits()); - pfd.setCAccumBits ((byte) accumDepth); - pfd.setCAccumRedBits ((byte) caps.getAccumRedBits()); - pfd.setCAccumGreenBits((byte) caps.getAccumGreenBits()); - pfd.setCAccumBlueBits ((byte) caps.getAccumBlueBits()); - pfd.setCAccumAlphaBits((byte) caps.getAccumAlphaBits()); - pfd.setCDepthBits((byte) caps.getDepthBits()); - pfd.setCStencilBits((byte) caps.getStencilBits()); - pfd.setILayerType((byte) GDI.PFD_MAIN_PLANE); - - // n/a with non ARB/GDI method: - // multisample - // opaque - // pbuffer - return pfd; - } - - static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor(long hdc, int pfdID) { - PIXELFORMATDESCRIPTOR pfd = PIXELFORMATDESCRIPTOR.create(); - pfd.setNSize((short) PIXELFORMATDESCRIPTOR.size()); - pfd.setNVersion((short) 1); - if(0 != hdc && 1 <= pfdID) { - if (WGLUtil.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { - // Accelerated pixel formats that are non displayable - if(DEBUG) { - System.err.println("Info: Non displayable pixel format " + pfdID + " of device context: error code " + GDI.GetLastError()); - } + static WGLGLCapabilities PFD2GLCapabilitiesNoCheck(AbstractGraphicsDevice device, final GLProfile glp, final long hdc, final int pfdID) { + PIXELFORMATDESCRIPTOR pfd = createPixelFormatDescriptor(hdc, pfdID); + return PFD2GLCapabilitiesNoCheck(device, glp, pfd, pfdID); + } + + static WGLGLCapabilities PFD2GLCapabilitiesNoCheck(AbstractGraphicsDevice device, GLProfile glp, PIXELFORMATDESCRIPTOR pfd, int pfdID) { + if(null == pfd) { return null; } - } - return pfd; - } - - static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor() { - return createPixelFormatDescriptor(0, 0); - } - - public String toString() { - return "WindowsWGLGraphicsConfiguration["+getScreen()+", pfdID " + getPixelFormatID() + ", ARB-Choosen " + isChoosenByARB() + - ",\n\trequested " + getRequestedCapabilities() + - ",\n\tchosen " + getChosenCapabilities() + - "]"; - } + final WGLGLCapabilities res = new WGLGLCapabilities(pfd, pfdID, glp); + res.setValuesByGDI(); + + return (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, PFD2DrawableTypeBits(pfd), res); + } + + static PIXELFORMATDESCRIPTOR GLCapabilities2PFD(GLCapabilitiesImmutable caps, PIXELFORMATDESCRIPTOR pfd) { + int colorDepth = (caps.getRedBits() + + caps.getGreenBits() + + caps.getBlueBits()); + if (colorDepth < 15) { + throw new GLException("Bit depths < 15 (i.e., non-true-color) not supported"); + } + int pfdFlags = ( GDI.PFD_SUPPORT_OPENGL | GDI.PFD_GENERIC_ACCELERATED ); + + if( caps.isOnscreen() ) { + pfdFlags |= GDI.PFD_DRAW_TO_WINDOW; + } else if( caps.isFBO() ) { + pfdFlags |= GDI.PFD_DRAW_TO_WINDOW; // native replacement! + } else if( caps.isPBuffer() ) { + pfdFlags |= GDI.PFD_DRAW_TO_BITMAP; // pbuffer n/a, use bitmap + } else if( caps.isBitmap() ) { + pfdFlags |= GDI.PFD_DRAW_TO_BITMAP; + } else { + throw new GLException("no surface type set in caps: "+caps); + } + + if ( caps.getDoubleBuffered() ) { + if( caps.isBitmap() || caps.isPBuffer() ) { + pfdFlags |= GDI.PFD_DOUBLEBUFFER_DONTCARE; // bitmaps probably don't have dbl buffering + } else { + pfdFlags |= GDI.PFD_DOUBLEBUFFER; + } + } + + if (caps.getStereo()) { + pfdFlags |= GDI.PFD_STEREO; + } + pfd.setDwFlags(pfdFlags); + pfd.setIPixelType((byte) GDI.PFD_TYPE_RGBA); + pfd.setCColorBits((byte) colorDepth); + pfd.setCRedBits ((byte) caps.getRedBits()); + pfd.setCGreenBits((byte) caps.getGreenBits()); + pfd.setCBlueBits ((byte) caps.getBlueBits()); + pfd.setCAlphaBits((byte) caps.getAlphaBits()); + int accumDepth = (caps.getAccumRedBits() + + caps.getAccumGreenBits() + + caps.getAccumBlueBits()); + pfd.setCAccumBits ((byte) accumDepth); + pfd.setCAccumRedBits ((byte) caps.getAccumRedBits()); + pfd.setCAccumGreenBits((byte) caps.getAccumGreenBits()); + pfd.setCAccumBlueBits ((byte) caps.getAccumBlueBits()); + pfd.setCAccumAlphaBits((byte) caps.getAccumAlphaBits()); + pfd.setCDepthBits((byte) caps.getDepthBits()); + pfd.setCStencilBits((byte) caps.getStencilBits()); + pfd.setILayerType((byte) GDI.PFD_MAIN_PLANE); + + // n/a with non ARB/GDI method: + // multisample + // opaque + // pbuffer + return pfd; + } + + static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor(long hdc, int pfdID) { + PIXELFORMATDESCRIPTOR pfd = PIXELFORMATDESCRIPTOR.create(); + pfd.setNSize((short) PIXELFORMATDESCRIPTOR.size()); + pfd.setNVersion((short) 1); + if(0 != hdc && 1 <= pfdID) { + if (WGLUtil.DescribePixelFormat(hdc, pfdID, PIXELFORMATDESCRIPTOR.size(), pfd) == 0) { + // Accelerated pixel formats that are non displayable + if(DEBUG) { + System.err.println("Info: Non displayable pixel format " + pfdID + " of device context: error code " + GDI.GetLastError()); + } + return null; + } + } + return pfd; + } + + static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor() { + return createPixelFormatDescriptor(0, 0); + } + + public String toString() { + return "WindowsWGLGraphicsConfiguration["+getScreen()+", pfdID " + getPixelFormatID() + ", ARB-Choosen " + isChoosenByARB() + + ",\n\trequested " + getRequestedCapabilities() + + ",\n\tchosen " + getChosenCapabilities() + + "]"; + } } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java index 00ed91bb4..d2d1dafc8 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfigurationFactory.java @@ -85,7 +85,11 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilities objects - requested"); } - return chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, chooser, absScreen); + if (chooser != null && !(chooser instanceof GLCapabilitiesChooser)) { + throw new IllegalArgumentException("This NativeWindowFactory accepts only GLCapabilitiesChooser objects"); + } + + return chooseGraphicsConfigurationStatic((GLCapabilitiesImmutable)capsChosen, (GLCapabilitiesImmutable)capsRequested, (GLCapabilitiesChooser)chooser, absScreen); } static WindowsWGLGraphicsConfiguration createDefaultGraphicsConfiguration(GLCapabilitiesImmutable caps, @@ -95,7 +99,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat static WindowsWGLGraphicsConfiguration chooseGraphicsConfigurationStatic(GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsReq, - CapabilitiesChooser chooser, + GLCapabilitiesChooser chooser, AbstractGraphicsScreen absScreen) { if(null==absScreen) { absScreen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS); @@ -109,13 +113,14 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(WindowsWGLDrawableFactory factory, AbstractGraphicsDevice device) { - WindowsWGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device); + final WindowsWGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device); if(null == sharedResource) { throw new GLException("Shared resource for device n/a: "+device); } - GLDrawableImpl sharedDrawable = sharedResource.getDrawable(); - GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities(); - GLContext sharedContext = sharedResource.getContext(); + final GLDrawableImpl sharedDrawable = sharedResource.getDrawable(); + final GLContext sharedContext = sharedResource.getContext(); + final GLProfile glp = GLProfile.getDefault(device); + List<GLCapabilitiesImmutable> availableCaps = null; if ( sharedResource.needsCurrentContext4ARBPFDQueries() ) { @@ -131,10 +136,10 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat throw new GLException("Error: HDC is null"); } if (sharedResource.hasARBPixelFormat()) { - availableCaps = getAvailableGLCapabilitiesARB(hdc, sharedResource, capsChosen.getGLProfile()); + availableCaps = WindowsWGLGraphicsConfigurationFactory.getAvailableGLCapabilitiesARB(sharedResource, sharedResource.getDevice(), glp, hdc); } if( null == availableCaps || availableCaps.isEmpty() ) { - availableCaps = getAvailableGLCapabilitiesGDI(hdc, capsChosen.getGLProfile()); + availableCaps = getAvailableGLCapabilitiesGDI(device, glp, hdc); } } finally { if ( sharedResource.needsCurrentContext4ARBPFDQueries() ) { @@ -150,17 +155,21 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat return availableCaps; } - static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesARB(long hdc, WindowsWGLDrawableFactory.SharedResource sharedResource, GLProfile glProfile) { - int[] pformats = WindowsWGLGraphicsConfiguration.wglAllARBPFIDs((WindowsWGLContext)sharedResource.getContext(), hdc); - return WindowsWGLGraphicsConfiguration.wglARBPFIDs2AllGLCapabilities(sharedResource, hdc, pformats, glProfile); + static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesARB(WindowsWGLDrawableFactory.SharedResource sharedResource, AbstractGraphicsDevice device, GLProfile glProfile, long hdc) { + final int pfdIDCount = WindowsWGLGraphicsConfiguration.wglARBPFDIDCount((WindowsWGLContext)sharedResource.getContext(), hdc); + final int[] pformats = WindowsWGLGraphicsConfiguration.wglAllARBPFDIDs(pfdIDCount); + return WindowsWGLGraphicsConfiguration.wglARBPFIDs2GLCapabilities(sharedResource, device, glProfile, hdc, pformats, GLGraphicsConfigurationUtil.ALL_BITS); } - static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesGDI(long hdc, GLProfile glProfile) { + static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesGDI(AbstractGraphicsDevice device, GLProfile glProfile, long hdc) { int[] pformats = WindowsWGLGraphicsConfiguration.wglAllGDIPFIDs(hdc); int numFormats = pformats.length; List<GLCapabilitiesImmutable> bucket = new ArrayList<GLCapabilitiesImmutable>(numFormats); for (int i = 0; i < numFormats; i++) { - WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(bucket, glProfile, hdc, pformats[i], GLGraphicsConfigurationUtil.ALL_BITS); + final GLCapabilitiesImmutable caps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pformats[i], GLGraphicsConfigurationUtil.ALL_BITS); + if(null != caps) { + bucket.add(caps); + } } return bucket; } @@ -274,8 +283,8 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } } try { - if( !updateGraphicsConfigurationARB(hdc, extHDC, config, chooser, (WindowsWGLDrawableFactory)factory, pfdIDs) ) { - updateGraphicsConfigurationGDI(hdc, extHDC, config, chooser, pfdIDs); + if( !updateGraphicsConfigurationARB((WindowsWGLDrawableFactory)factory, config, chooser, hdc, extHDC, pfdIDs) ) { + updateGraphicsConfigurationGDI(config, chooser, hdc, extHDC, pfdIDs); } } finally { if (null != sharedContext) { @@ -284,10 +293,10 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } } - private static boolean updateGraphicsConfigurationARB(long hdc, boolean extHDC, WindowsWGLGraphicsConfiguration config, - CapabilitiesChooser chooser, WindowsWGLDrawableFactory factory, int[] pformats) { - AbstractGraphicsDevice device = config.getScreen().getDevice(); - WindowsWGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device); + private static boolean updateGraphicsConfigurationARB(WindowsWGLDrawableFactory factory, WindowsWGLGraphicsConfiguration config, CapabilitiesChooser chooser, + long hdc, boolean extHDC, int[] pformats) { + final AbstractGraphicsDevice device = config.getScreen().getDevice(); + final WindowsWGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateSharedResource(device); if (null == sharedResource) { if (DEBUG) { @@ -302,16 +311,25 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat return false; } - GLCapabilitiesImmutable capsChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities(); - boolean isOpaque = capsChosen.isBackgroundOpaque() && GDI.DwmIsCompositionEnabled(); - boolean onscreen = capsChosen.isOnscreen(); - boolean usePBuffer = capsChosen.isPBuffer(); - GLProfile glProfile = capsChosen.getGLProfile(); + final GLCapabilitiesImmutable capsChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final boolean isOpaque = capsChosen.isBackgroundOpaque() && GDI.DwmIsCompositionEnabled(); + final int winattrbits = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen); + final GLProfile glProfile = capsChosen.getGLProfile(); + + final int pfdIDCount = WindowsWGLGraphicsConfiguration.wglARBPFDIDCount((WindowsWGLContext)sharedResource.getContext(), hdc); if(DEBUG) { - System.err.println("translucency requested: "+(!capsChosen.isBackgroundOpaque())+", compositioning enabled: "+GDI.DwmIsCompositionEnabled()+" -> translucency "+(!isOpaque)); + System.err.println("updateGraphicsConfigurationARB: hdc "+toHexString(hdc)+", pfdIDCount(hdc) "+pfdIDCount+", capsChosen "+capsChosen+", "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrbits).toString()); + System.err.println("isOpaque "+isOpaque+" (translucency requested: "+(!capsChosen.isBackgroundOpaque())+", compositioning enabled: "+GDI.DwmIsCompositionEnabled()+")"); } + if(0 >= pfdIDCount) { + if (DEBUG) { + System.err.println("updateGraphicsConfigurationARB: failed due to 0 pfdIDs for hdc "+toHexString(hdc)+" - hdc incompatible w/ ARB ext."); + } + return false; + } + WGLGLCapabilities pixelFormatCaps = null; // chosen or preset PFD ID's caps boolean pixelFormatSet = false; // indicates a preset PFD ID [caps] final int presetPFDID = extHDC ? -1 : WGLUtil.GetPixelFormat(hdc) ; @@ -325,7 +343,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat + ", pixelformat " + presetPFDID); } pixelFormatSet = true; - pixelFormatCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, hdc, presetPFDID, glProfile, onscreen, usePBuffer); + pixelFormatCaps = WindowsWGLGraphicsConfiguration.wglARBPFID2GLCapabilities(sharedResource, device, glProfile, hdc, presetPFDID, winattrbits); pixelFormatCaps = (WGLGLCapabilities) GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(pixelFormatCaps, isOpaque); } else { int recommendedIndex = -1; // recommended index @@ -337,17 +355,17 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat int[] iattributes = new int[2 * WindowsWGLGraphicsConfiguration.MAX_ATTRIBS]; float[] fattributes = new float[1]; int accelerationMode = WGLExt.WGL_FULL_ACCELERATION_ARB; - pformats = WindowsWGLGraphicsConfiguration.wglChoosePixelFormatARB(hdc, sharedResource, capsChosen, - iattributes, accelerationMode, fattributes); + pformats = WindowsWGLGraphicsConfiguration.wglChoosePixelFormatARB(sharedResource, device, capsChosen, + hdc, iattributes, accelerationMode, fattributes); if (null == pformats) { accelerationMode = WGLExt.WGL_GENERIC_ACCELERATION_ARB; - pformats = WindowsWGLGraphicsConfiguration.wglChoosePixelFormatARB(hdc, sharedResource, capsChosen, - iattributes, accelerationMode, fattributes); + pformats = WindowsWGLGraphicsConfiguration.wglChoosePixelFormatARB(sharedResource, device, capsChosen, + hdc, iattributes, accelerationMode, fattributes); } if (null == pformats) { accelerationMode = -1; // use what we are offered .. - pformats = WindowsWGLGraphicsConfiguration.wglChoosePixelFormatARB(hdc, sharedResource, capsChosen, - iattributes, accelerationMode, fattributes); + pformats = WindowsWGLGraphicsConfiguration.wglChoosePixelFormatARB(sharedResource, device, capsChosen, + hdc, iattributes, accelerationMode, fattributes); } if (null != pformats) { recommendedIndex = 0; @@ -356,7 +374,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat System.err.println("updateGraphicsConfigurationARB: wglChoosePixelFormatARB failed with: "+capsChosen); } // 2nd choice: get all GLCapabilities available, no preferred recommendedIndex available - pformats = WindowsWGLGraphicsConfiguration.wglAllARBPFIDs((WindowsWGLContext)sharedResource.getContext(), hdc); + pformats = WindowsWGLGraphicsConfiguration.wglAllARBPFDIDs(pfdIDCount); if (DEBUG) { final int len = ( null != pformats ) ? pformats.length : 0; System.err.println("updateGraphicsConfigurationARB: NumFormats (wglAllARBPFIDs) " + len); @@ -371,13 +389,12 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } } - List<GLCapabilitiesImmutable> availableCaps = - WindowsWGLGraphicsConfiguration.wglARBPFIDs2GLCapabilities(sharedResource, hdc, pformats, - glProfile, onscreen, usePBuffer); + List<GLCapabilitiesImmutable> availableCaps = + WindowsWGLGraphicsConfiguration.wglARBPFIDs2GLCapabilities(sharedResource, device, glProfile, hdc, pformats, winattrbits); + if( null == availableCaps || 0 == availableCaps.size() ) { if (DEBUG) { - System.err.println("updateGraphicsConfigurationARB: wglARBPFIDs2GLCapabilities failed with " + pformats.length + - " pfd ids, onscreen " + onscreen + ", pbuffer " + usePBuffer); + System.err.println("updateGraphicsConfigurationARB: wglARBPFIDs2GLCapabilities failed with " + pformats.length + " pfd ids"); Thread.dumpStack(); } return false; @@ -385,7 +402,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat if (DEBUG) { System.err.println("updateGraphicsConfigurationARB: " + pformats.length + - " pfd ids, onscreen " + onscreen + ", pbuffer " + usePBuffer + ", " + availableCaps.size() + " glcaps"); + " pfd ids, " + GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrbits).toString() + ", " + availableCaps.size() + " glcaps"); if(0 <= recommendedIndex) { System.err.println("updateGraphicsConfigurationARB: Used wglChoosePixelFormatARB to recommend pixel format " + pformats[recommendedIndex] + ", idx " + recommendedIndex +", "+availableCaps.get(recommendedIndex)); @@ -420,19 +437,25 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat return true; } - private static boolean updateGraphicsConfigurationGDI(long hdc, boolean extHDC, WindowsWGLGraphicsConfiguration config, - CapabilitiesChooser chooser, int[] pformats) { + private static boolean updateGraphicsConfigurationGDI(WindowsWGLGraphicsConfiguration config, CapabilitiesChooser chooser, long hdc, + boolean extHDC, int[] pformats) { GLCapabilitiesImmutable capsChosen = (GLCapabilitiesImmutable) config.getChosenCapabilities(); - if(capsChosen.isPBuffer()) { + if( !capsChosen.isOnscreen() && capsChosen.isPBuffer() ) { if (DEBUG) { System.err.println("updateGraphicsConfigurationGDI: no pbuffer supported on GDI: " + capsChosen); } return false; } - boolean onscreen = capsChosen.isOnscreen(); - GLProfile glProfile = capsChosen.getGLProfile(); - - List<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); + // final boolean onscreen = capsChosen.isOnscreen(); + // final boolean useFBO = capsChosen.isFBO(); + final GLProfile glProfile = capsChosen.getGLProfile(); + final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen); + + if(DEBUG) { + System.err.println("updateGraphicsConfigurationGDI: capsChosen "+capsChosen+", "+GLGraphicsConfigurationUtil.winAttributeBits2String(null, winattrmask).toString()); + } + + AbstractGraphicsDevice device = config.getScreen().getDevice(); int pfdID; // chosen or preset PFD ID WGLGLCapabilities pixelFormatCaps = null; // chosen or preset PFD ID's caps boolean pixelFormatSet = false; // indicates a preset PFD ID [caps] @@ -447,15 +470,29 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat + ", pixelformat " + pfdID); } pixelFormatSet = true; - pixelFormatCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(glProfile, hdc, pfdID, onscreen); + pixelFormatCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pfdID, winattrmask); + if(null == pixelFormatCaps) { + throw new GLException("Could not map PFD2GLCaps w/ already chosen pfdID "+pfdID); + } } else { - if(null == pformats) { + final boolean givenPFormats = null != pformats; + if( !givenPFormats ) { pformats = WindowsWGLGraphicsConfiguration.wglAllGDIPFIDs(hdc); } - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, false, false); + List<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); for (int i = 0; i < pformats.length; i++) { - WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(availableCaps, glProfile, hdc, pformats[i], winattrmask); + final GLCapabilitiesImmutable caps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pformats[i], winattrmask); + if(null != caps) { + availableCaps.add(caps); + if(DEBUG) { + final int j = availableCaps.size() - 1; + System.err.println("updateGraphicsConfigurationGDI: availableCaps["+i+" -> "+j+"]: "+caps); + } + } else if(DEBUG) { + GLCapabilitiesImmutable skipped = WindowsWGLGraphicsConfiguration.PFD2GLCapabilitiesNoCheck(device, glProfile, hdc, pformats[i]); + System.err.println("updateGraphicsConfigurationGDI: availableCaps["+i+" -> skip]: pfdID "+pformats[i]+", "+skipped); + } } // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice @@ -464,16 +501,21 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat pfdID = WGLUtil.ChoosePixelFormat(hdc, pfd); int recommendedIndex = -1 ; if( 1 <= pfdID ) { - // seek index .. + // seek index .. in all formats _or_ in given formats! for (recommendedIndex = availableCaps.size() - 1 ; 0 <= recommendedIndex && pfdID != ((WGLGLCapabilities) availableCaps.get(recommendedIndex)).getPFDID(); recommendedIndex--) { /* nop */ } + if(DEBUG && 0 > recommendedIndex) { + final GLCapabilitiesImmutable reqPFDCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilitiesNoCheck(device, glProfile, pfd, pfdID); + final GLCapabilitiesImmutable chosenCaps = WindowsWGLGraphicsConfiguration.PFD2GLCapabilities(device, glProfile, hdc, pfdID, winattrmask); + System.err.println("Chosen PFDID "+pfdID+", but not found in available caps (use given pfdIDs "+givenPFormats+", reqPFDCaps "+reqPFDCaps+", chosenCaps: "+chosenCaps); + } } - // 2nd choice: if no preferred recommendedIndex available if (DEBUG) { - System.err.println("updateGraphicsConfigurationGDI: ChoosePixelFormat(HDC " + toHexString(hdc) + ") = " + pfdID + ", idx " + recommendedIndex + " (LastError: " + GDI.GetLastError() + ")"); + System.err.println("updateGraphicsConfigurationGDI: ChoosePixelFormat(HDC " + toHexString(hdc) + ") = pfdID " + pfdID + ", idx " + recommendedIndex + " (LastError: " + GDI.GetLastError() + ")"); } + // 2nd choice: if no preferred recommendedIndex available int chosenIndex = chooseCapabilities(chooser, capsChosen, availableCaps, recommendedIndex); if ( 0 > chosenIndex ) { if (DEBUG) { @@ -484,8 +526,7 @@ public class WindowsWGLGraphicsConfigurationFactory extends GLGraphicsConfigurat } pixelFormatCaps = (WGLGLCapabilities) availableCaps.get(chosenIndex); if (DEBUG) { - System.err.println("chosen pfdID (GDI): native recommended "+ (recommendedIndex+1) + - ", caps " + pixelFormatCaps); + System.err.println("chosen pfdID (GDI): chosenIndex "+ chosenIndex + ", caps " + pixelFormatCaps); } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java index 1f3edbd8a..03a0eefbf 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXContext.java @@ -48,10 +48,10 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLContextShareSet; -import com.jogamp.nativewindow.WrappedSurface; import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11ExternalGLXContext extends X11GLXContext { @@ -105,7 +105,7 @@ public class X11ExternalGLXContext extends X11GLXContext { cfg = X11GLXGraphicsConfiguration.create(glp, x11Screen, val[0]); } - final WrappedSurface ns = new WrappedSurface(cfg, drawable, w, h, null); + final WrappedSurface ns = new WrappedSurface(cfg, drawable, w, h, true); return new X11ExternalGLXContext(new Drawable(factory, ns), ctx); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java index 8652e2d4a..ac78c6f4a 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java @@ -45,7 +45,8 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import com.jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.WrappedSurface; + import com.jogamp.nativewindow.x11.X11GraphicsScreen; @@ -87,7 +88,7 @@ public class X11ExternalGLXDrawable extends X11GLXDrawable { System.err.println("X11ExternalGLXDrawable: WARNING: forcing GLX_RGBA_TYPE for newly created contexts (current 0x"+Integer.toHexString(val[0])+")"); } } - return new X11ExternalGLXDrawable(factory, new WrappedSurface(cfg, drawable, w, h, null)); + return new X11ExternalGLXDrawable(factory, new WrappedSurface(cfg, drawable, w, h, true)); } @Override diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java index e9912ce9d..8c642777d 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java @@ -69,9 +69,10 @@ public abstract class X11GLXDrawable extends GLDrawableImpl { } @Override - protected final void swapBuffersImpl() { - // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() - GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); + protected final void swapBuffersImpl(boolean doubleBuffered) { + if(doubleBuffered) { + GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); + } } //--------------------------------------------------------------------------- diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 293ac96f7..fb11f8bba 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -49,7 +49,7 @@ import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; -import javax.media.nativewindow.ProxySurface.UpstreamSurfaceHook; +import javax.media.nativewindow.UpstreamSurfaceHook; import javax.media.nativewindow.VisualIDHolder; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; @@ -58,8 +58,9 @@ import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import javax.media.opengl.GLProfile.ShutdownType; +import jogamp.nativewindow.WrappedSurface; +import jogamp.nativewindow.x11.X11DummyUpstreamSurfaceHook; import jogamp.nativewindow.x11.X11Lib; import jogamp.nativewindow.x11.X11Util; import jogamp.opengl.DesktopGLDynamicLookupHelper; @@ -71,7 +72,6 @@ import jogamp.opengl.GLGraphicsConfigurationUtil; import jogamp.opengl.SharedResourceRunner; import com.jogamp.common.util.VersionNumber; -import com.jogamp.nativewindow.WrappedSurface; import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; @@ -129,7 +129,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { } @Override - protected final void destroy(ShutdownType shutdownType) { + protected final void destroy() { if(null != sharedResourceRunner) { sharedResourceRunner.stop(); sharedResourceRunner = null; @@ -142,14 +142,9 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { /** * Pulling away the native library may cause havoc .. * - if(ShutdownType.COMPLETE == shutdownType && null != x11GLXDynamicLookupHelper) { - x11GLXDynamicLookupHelper.destroy(); - x11GLXDynamicLookupHelper = null; - } */ - - // Don't really close pending Display connections, - // since this may trigger a JVM exception - X11Util.shutdown( false, DEBUG ); + x11GLXDynamicLookupHelper.destroy(); + */ + x11GLXDynamicLookupHelper = null; } @Override @@ -511,7 +506,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { protected final ProxySurface createMutableSurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, - GLCapabilitiesChooser chooser, int width, int height, UpstreamSurfaceHook lifecycleHook) { + GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstreamHook) { final X11GraphicsDevice device; if(createNewDevice) { // Null X11 locking, due to private non-shared Display handle @@ -524,65 +519,15 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { if(null == config) { throw new GLException("Choosing GraphicsConfiguration failed w/ "+capsChosen+" on "+screen); } - return new WrappedSurface( config, 0, width, height, lifecycleHook); + return new WrappedSurface(config, 0, upstreamHook, createNewDevice); } @Override public final ProxySurface createDummySurfaceImpl(AbstractGraphicsDevice deviceReq, boolean createNewDevice, GLCapabilitiesImmutable requestedCaps, GLCapabilitiesChooser chooser, int width, int height) { final GLCapabilitiesImmutable chosenCaps = GLGraphicsConfigurationUtil.fixOnscreenGLCapabilities(requestedCaps); - return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, width, height, dummySurfaceLifecycleHook); + return createMutableSurfaceImpl(deviceReq, createNewDevice, chosenCaps, requestedCaps, chooser, new X11DummyUpstreamSurfaceHook(width, height)); } - private static final ProxySurface.UpstreamSurfaceHook dummySurfaceLifecycleHook = new ProxySurface.UpstreamSurfaceHook() { - @Override - public final void create(ProxySurface s) { - if( 0 == s.getSurfaceHandle() ) { - final X11GLXGraphicsConfiguration cfg = (X11GLXGraphicsConfiguration) s.getGraphicsConfiguration(); - final X11GraphicsScreen screen = (X11GraphicsScreen) cfg.getScreen(); - final X11GraphicsDevice device = (X11GraphicsDevice) screen.getDevice(); - if(0 == device.getHandle()) { - device.open(); - s.setImplBitfield(ProxySurface.OWN_DEVICE); - } - final long windowHandle = X11Lib.CreateDummyWindow(device.getHandle(), screen.getIndex(), cfg.getXVisualID(), s.getWidth(), s.getHeight()); - if(0 == windowHandle) { - throw new GLException("Creating dummy window failed w/ "+cfg+", "+s.getWidth()+"x"+s.getHeight()); - } - s.setSurfaceHandle(windowHandle); - if(DEBUG) { - System.err.println("X11GLXDrawableFactory.dummySurfaceLifecycleHook.create: "+s); - } - } - } - @Override - public final void destroy(ProxySurface s) { - if(0 != s.getSurfaceHandle()) { - final X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) s.getGraphicsConfiguration(); - final X11GraphicsDevice device = (X11GraphicsDevice) config.getScreen().getDevice(); - X11Lib.DestroyDummyWindow(device.getHandle(), s.getSurfaceHandle()); - s.setSurfaceHandle(0); - if( 0 != ( ProxySurface.OWN_DEVICE & s.getImplBitfield() ) ) { - device.close(); - } - if(DEBUG) { - System.err.println("X11GLXDrawableFactory.dummySurfaceLifecycleHook.destroy: "+s); - } - } - } - @Override - public final int getWidth(ProxySurface s) { - return s.initialWidth; - } - @Override - public final int getHeight(ProxySurface s) { - return s.initialHeight; - } - @Override - public String toString() { - return "X11SurfaceLifecycleHook[]"; - } - }; - @Override protected final ProxySurface createProxySurfaceImpl(AbstractGraphicsDevice deviceReq, int screenIdx, long windowHandle, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, UpstreamSurfaceHook upstream) { @@ -599,7 +544,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { if(DEBUG) { System.err.println("X11GLXDrawableFactory.createProxySurfaceImpl 0x"+Long.toHexString(windowHandle)+": "+cfg); } - return new WrappedSurface(cfg, windowHandle, 0, 0, upstream); + return new WrappedSurface(cfg, windowHandle, upstream, true); } @Override diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java index b458fffe1..96c3c4123 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfiguration.java @@ -33,10 +33,6 @@ package jogamp.opengl.x11.glx; -import java.util.ArrayList; -import java.util.List; - -import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; import javax.media.nativewindow.VisualIDHolder; @@ -45,7 +41,6 @@ import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; -import javax.media.opengl.GLContext; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; @@ -58,6 +53,7 @@ import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.nio.PointerBuffer; import com.jogamp.nativewindow.x11.X11GraphicsConfiguration; +import com.jogamp.nativewindow.x11.X11GraphicsDevice; import com.jogamp.nativewindow.x11.X11GraphicsScreen; public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implements Cloneable { @@ -70,28 +66,6 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem this.chooser=chooser; } - static X11GLXGraphicsConfiguration create(GLProfile glp, X11GraphicsScreen x11Screen, int fbcfgID) { - final AbstractGraphicsDevice device = x11Screen.getDevice(); - final long display = device.getHandle(); - if(0==display) { - throw new GLException("Display null of "+x11Screen); - } - final int screen = x11Screen.getIndex(); - final long fbcfg = glXFBConfigID2FBConfig(display, screen, fbcfgID); - if(0==fbcfg) { - throw new GLException("FBConfig null of "+toHexString(fbcfgID)); - } - if(null==glp) { - glp = GLProfile.getDefault(x11Screen.getDevice()); - } - final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); - final X11GLCapabilities caps = GLXFBConfig2GLCapabilities(glp, device, fbcfg, true, true, true, factory.isGLXMultisampleAvailable(device)); - if(null==caps) { - throw new GLException("GLCapabilities null of "+toHexString(fbcfg)); - } - return new X11GLXGraphicsConfiguration(x11Screen, caps, caps, new DefaultGLCapabilitiesChooser()); - } - public Object clone() { return super.clone(); } @@ -126,11 +100,31 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem } } + static X11GLXGraphicsConfiguration create(GLProfile glp, X11GraphicsScreen x11Screen, int fbcfgID) { + final X11GraphicsDevice device = (X11GraphicsDevice) x11Screen.getDevice(); + final long display = device.getHandle(); + if(0==display) { + throw new GLException("Display null of "+x11Screen); + } + final int screen = x11Screen.getIndex(); + final long fbcfg = glXFBConfigID2FBConfig(display, screen, fbcfgID); + if(0==fbcfg) { + throw new GLException("FBConfig null of "+toHexString(fbcfgID)); + } + if(null==glp) { + glp = GLProfile.getDefault(x11Screen.getDevice()); + } + final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); + final X11GLCapabilities caps = GLXFBConfig2GLCapabilities(device, glp, fbcfg, GLGraphicsConfigurationUtil.ALL_BITS, factory.isGLXMultisampleAvailable(device)); + if(null==caps) { + throw new GLException("GLCapabilities null of "+toHexString(fbcfg)); + } + return new X11GLXGraphicsConfiguration(x11Screen, caps, caps, new DefaultGLCapabilitiesChooser()); + } + static int[] GLCapabilities2AttribList(GLCapabilitiesImmutable caps, - boolean forFBAttr, - boolean isMultisampleAvailable, - long display, - int screen) + boolean forFBAttr, boolean isMultisampleAvailable, + long display, int screen) { int colorDepth = (caps.getRedBits() + caps.getGreenBits() + @@ -143,10 +137,21 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem if (forFBAttr) { res[idx++] = GLX.GLX_DRAWABLE_TYPE; - res[idx++] = caps.isOnscreen() ? ( GLX.GLX_WINDOW_BIT ) : ( caps.isPBuffer() ? GLX.GLX_PBUFFER_BIT : GLX.GLX_PIXMAP_BIT ) ; - } - - if (forFBAttr) { + + final int surfaceType; + if( caps.isOnscreen() ) { + surfaceType = GLX.GLX_WINDOW_BIT; + } else if( caps.isFBO() ) { + surfaceType = GLX.GLX_WINDOW_BIT; // native replacement! + } else if( caps.isPBuffer() ) { + surfaceType = GLX.GLX_PBUFFER_BIT; + } else if( caps.isBitmap() ) { + surfaceType = GLX.GLX_PIXMAP_BIT; + } else { + throw new GLException("no surface type set in caps: "+caps); + } + res[idx++] = surfaceType; + res[idx++] = GLX.GLX_RENDER_TYPE; res[idx++] = GLX.GLX_RGBA_BIT; } else { @@ -247,14 +252,15 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem return true; } - static int FBCfgDrawableTypeBits(final AbstractGraphicsDevice device, GLProfile glp, final long fbcfg) { + static int FBCfgDrawableTypeBits(final X11GraphicsDevice device, final long fbcfg) { int val = 0; int[] tmp = new int[1]; int fbtype = glXGetFBConfig(device.getHandle(), fbcfg, GLX.GLX_DRAWABLE_TYPE, tmp, 0); if ( 0 != ( fbtype & GLX.GLX_WINDOW_BIT ) ) { - val |= GLGraphicsConfigurationUtil.WINDOW_BIT; + val |= GLGraphicsConfigurationUtil.WINDOW_BIT | + GLGraphicsConfigurationUtil.FBO_BIT; } if ( 0 != ( fbtype & GLX.GLX_PIXMAP_BIT ) ) { val |= GLGraphicsConfigurationUtil.BITMAP_BIT; @@ -262,25 +268,9 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem if ( 0 != ( fbtype & GLX.GLX_PBUFFER_BIT ) ) { val |= GLGraphicsConfigurationUtil.PBUFFER_BIT; } - if ( GLContext.isFBOAvailable(device, glp) ) { - val |= GLGraphicsConfigurationUtil.FBO_BIT; - } return val; } - static X11GLCapabilities GLXFBConfig2GLCapabilities(GLProfile glp, AbstractGraphicsDevice device, long fbcfg, - boolean relaxed, boolean onscreen, boolean usePBuffer, - boolean isMultisampleAvailable) { - ArrayList<GLCapabilitiesImmutable> bucket = new ArrayList<GLCapabilitiesImmutable>(); - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, false); - if( GLXFBConfig2GLCapabilities(bucket, glp, device, fbcfg, winattrmask, isMultisampleAvailable) ) { - return (X11GLCapabilities) bucket.get(0); - } else if ( relaxed && GLXFBConfig2GLCapabilities(bucket, glp, device, fbcfg, GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable) ) { - return (X11GLCapabilities) bucket.get(0); - } - return null; - } - static XRenderDirectFormat XVisual2XRenderMask(long dpy, long visual) { XRenderPictFormat renderPictFmt = X11Lib.XRenderFindVisualFormat(dpy, visual); if(null == renderPictFmt) { @@ -289,10 +279,9 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem return renderPictFmt.getDirect(); } - static boolean GLXFBConfig2GLCapabilities(List<GLCapabilitiesImmutable> capsBucket, - GLProfile glp, AbstractGraphicsDevice device, long fbcfg, - int winattrmask, boolean isMultisampleAvailable) { - final int allDrawableTypeBits = FBCfgDrawableTypeBits(device, glp, fbcfg); + static X11GLCapabilities GLXFBConfig2GLCapabilities(X11GraphicsDevice device, GLProfile glp, long fbcfg, + int winattrmask, boolean isMultisampleAvailable) { + final int allDrawableTypeBits = FBCfgDrawableTypeBits(device, fbcfg); int drawableTypeBits = winattrmask & allDrawableTypeBits; final long display = device.getHandle(); @@ -303,22 +292,22 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem System.err.println("X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities: Null XVisualInfo for FBConfigID 0x" + Integer.toHexString(fbcfgid)); } // onscreen must have an XVisualInfo - drawableTypeBits = drawableTypeBits & ~GLGraphicsConfigurationUtil.WINDOW_BIT; + drawableTypeBits &= ~(GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.FBO_BIT); } if( 0 == drawableTypeBits ) { - return false; + return null; } int[] tmp = new int[1]; if(GLX.GLX_BAD_ATTRIBUTE == GLX.glXGetFBConfigAttrib(display, fbcfg, GLX.GLX_RENDER_TYPE, tmp, 0)) { - return false; + return null; } if( 0 == ( GLX.GLX_RGBA_BIT & tmp[0] ) ) { - return false; // no RGBA -> color index not supported + return null; // no RGBA -> color index not supported } - GLCapabilities res = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp); + final X11GLCapabilities res = new X11GLCapabilities(visualInfo, fbcfg, fbcfgid, glp); if (isMultisampleAvailable) { res.setSampleBuffers(glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLE_BUFFERS, tmp, 0) != 0); res.setNumSamples (glXGetFBConfig(display, fbcfg, GLX.GLX_SAMPLES, tmp, 0)); @@ -353,7 +342,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem res.setPbufferFloatingPointBuffers(glXGetFBConfig(display, fbcfg, GLXExt.GLX_FLOAT_COMPONENTS_NV, tmp, 0) != GL.GL_FALSE); } catch (Exception e) {} - return GLGraphicsConfigurationUtil.addGLCapabilitiesPermutations(capsBucket, res, drawableTypeBits ); + return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res); } private static String glXGetFBConfigErrorCode(int err) { @@ -408,30 +397,33 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem return res; } - static boolean XVisualInfo2GLCapabilities(List<GLCapabilitiesImmutable> capsBucket, - GLProfile glp, long display, XVisualInfo info, - final int winattrmask, boolean isMultisampleEnabled) { - final int allDrawableTypeBits = GLGraphicsConfigurationUtil.WINDOW_BIT | GLGraphicsConfigurationUtil.BITMAP_BIT ; + static X11GLCapabilities XVisualInfo2GLCapabilities(final X11GraphicsDevice device, GLProfile glp, XVisualInfo info, + final int winattrmask, boolean isMultisampleEnabled) { + final int allDrawableTypeBits = GLGraphicsConfigurationUtil.WINDOW_BIT | + GLGraphicsConfigurationUtil.BITMAP_BIT | + GLGraphicsConfigurationUtil.FBO_BIT ; + final int drawableTypeBits = winattrmask & allDrawableTypeBits; if( 0 == drawableTypeBits ) { - return false; + return null; } + final long display = device.getHandle(); int[] tmp = new int[1]; int val = glXGetConfig(display, info, GLX.GLX_USE_GL, tmp, 0); if (val == 0) { if(DEBUG) { System.err.println("Visual ("+toHexString(info.getVisualid())+") does not support OpenGL"); } - return false; + return null; } val = glXGetConfig(display, info, GLX.GLX_RGBA, tmp, 0); if (val == 0) { if(DEBUG) { System.err.println("Visual ("+toHexString(info.getVisualid())+") does not support RGBA"); } - return false; + return null; } GLCapabilities res = new X11GLCapabilities(info, glp); @@ -470,7 +462,7 @@ public class X11GLXGraphicsConfiguration extends X11GraphicsConfiguration implem res.setAccumBlueBits (glXGetConfig(display, info, GLX.GLX_ACCUM_BLUE_SIZE, tmp, 0)); res.setAccumAlphaBits(glXGetConfig(display, info, GLX.GLX_ACCUM_ALPHA_SIZE, tmp, 0)); - return GLGraphicsConfigurationUtil.addGLCapabilitiesPermutations(capsBucket, res, drawableTypeBits); + return (X11GLCapabilities) GLGraphicsConfigurationUtil.fixWinAttribBitsAndHwAccel(device, drawableTypeBits, res); } private static String glXGetConfigErrorCode(int err) { diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java index 234b06bdb..431706e24 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXGraphicsConfigurationFactory.java @@ -129,9 +129,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } final X11GraphicsScreen sharedScreen = (X11GraphicsScreen) sharedResource.getScreen(); final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(sharedScreen.getDevice()); - final X11GLXDrawable sharedDrawable = (X11GLXDrawable) sharedResource.getDrawable(); - final GLCapabilitiesImmutable capsChosen = sharedDrawable.getChosenGLCapabilities(); - final GLProfile glp = capsChosen.getGLProfile(); + final GLProfile glp = GLProfile.getDefault(device); List<GLCapabilitiesImmutable> availableCaps = null; @@ -152,12 +150,12 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF // Utilizing FBConfig // - AbstractGraphicsDevice absDevice = x11Screen.getDevice(); - long display = absDevice.getHandle(); + final X11GraphicsDevice absDevice = (X11GraphicsDevice) x11Screen.getDevice(); + final long display = absDevice.getHandle(); - int screen = x11Screen.getIndex(); - int[] count = { -1 }; - ArrayList<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); + final int screen = x11Screen.getIndex(); + final int[] count = { -1 }; + final ArrayList<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); fbcfgsL = GLX.glXChooseFBConfig(display, screen, null, 0, count, 0); if (fbcfgsL == null || fbcfgsL.limit()<=0) { @@ -167,18 +165,19 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF return null; } for (int i = 0; i < fbcfgsL.limit(); i++) { - if( !X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(availableCaps, glProfile, absDevice, fbcfgsL.get(i), GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable) ) { - if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); - } + final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(absDevice, glProfile, fbcfgsL.get(i), GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable); + if(null != caps) { + availableCaps.add(caps); + } else if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); } } return availableCaps; } static List<GLCapabilitiesImmutable> getAvailableGLCapabilitiesXVisual(X11GraphicsScreen x11Screen, GLProfile glProfile, boolean isMultisampleAvailable) { - AbstractGraphicsDevice absDevice = x11Screen.getDevice(); - long display = absDevice.getHandle(); + final X11GraphicsDevice absDevice = (X11GraphicsDevice) x11Screen.getDevice(); + final long display = absDevice.getHandle(); int screen = x11Screen.getIndex(); @@ -191,10 +190,11 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } ArrayList<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); for (int i = 0; i < infos.length; i++) { - if( !X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities(availableCaps, glProfile, display, infos[i], GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable) ) { - if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesXVisual: XVisual invalid: ("+x11Screen+"): fbcfg: "+toHexString(infos[i].getVisualid())); - } + final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities(absDevice, glProfile, infos[i], GLGraphicsConfigurationUtil.ALL_BITS, isMultisampleAvailable); + if(null != caps) { + availableCaps.add(caps); + } if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.getAvailableGLCapabilitiesXVisual: XVisual invalid: ("+x11Screen+"): fbcfg: "+toHexString(infos[i].getVisualid())); } } return availableCaps; @@ -208,7 +208,6 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF if (x11Screen == null) { throw new IllegalArgumentException("AbstractGraphicsScreen is null"); } - if (capsChosen == null) { capsChosen = new GLCapabilities(null); } @@ -216,7 +215,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); capsChosen = GLGraphicsConfigurationUtil.fixGLCapabilities( capsChosen, GLContext.isFBOAvailable(x11Device, capsChosen.getGLProfile()), factory.canCreateGLPbuffer(x11Device) ); - boolean usePBuffer = capsChosen.isPBuffer(); + boolean usePBuffer = !capsChosen.isOnscreen() && capsChosen.isPBuffer(); X11GLXGraphicsConfiguration res = null; if( factory.isGLXVersionGreaterEqualOneThree(x11Device) ) { @@ -238,8 +237,8 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } static X11GLXGraphicsConfiguration fetchGraphicsConfigurationFBConfig(X11GraphicsScreen x11Screen, int fbID, GLProfile glp) { - final AbstractGraphicsDevice absDevice = x11Screen.getDevice(); - final long display = absDevice.getHandle(); + final X11GraphicsDevice x11Device = (X11GraphicsDevice) x11Screen.getDevice(); + final long display = x11Device.getHandle(); final int screen = x11Screen.getIndex(); final long fbcfg = X11GLXGraphicsConfiguration.glXFBConfigID2FBConfig(display, screen, fbID); @@ -251,7 +250,7 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); - final X11GLCapabilities caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(glp, absDevice, fbcfg, true, true, true, factory.isGLXMultisampleAvailable(absDevice)); + final X11GLCapabilities caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glp, fbcfg, GLGraphicsConfigurationUtil.ALL_BITS, factory.isGLXMultisampleAvailable(x11Device)); return new X11GLXGraphicsConfiguration(x11Screen, caps, caps, new DefaultGLCapabilitiesChooser()); } @@ -262,22 +261,19 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF int recommendedIndex = -1; PointerBuffer fbcfgsL = null; GLProfile glProfile = capsChosen.getGLProfile(); - boolean onscreen = capsChosen.isOnscreen(); - boolean usePBuffer = capsChosen.isPBuffer(); - boolean useFBO = capsChosen.isFBO(); // Utilizing FBConfig // - AbstractGraphicsDevice absDevice = x11Screen.getDevice(); - long display = absDevice.getHandle(); + X11GraphicsDevice x11Device = (X11GraphicsDevice) x11Screen.getDevice(); + long display = x11Device.getHandle(); int screen = x11Screen.getIndex(); final X11GLXDrawableFactory factory = (X11GLXDrawableFactory) GLDrawableFactory.getDesktopFactory(); - final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(absDevice); + final boolean isMultisampleAvailable = factory.isGLXMultisampleAvailable(x11Device); int[] attribs = X11GLXGraphicsConfiguration.GLCapabilities2AttribList(capsChosen, true, isMultisampleAvailable, display, screen); int[] count = { -1 }; List<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(onscreen, usePBuffer, useFBO); + final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen); // 1st choice: get GLCapabilities based on users GLCapabilities setting recommendedIndex as preferred choice, // skipped if xvisualID is given if( VisualIDHolder.VID_UNDEFINED == xvisualID ) { @@ -285,10 +281,11 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } if (fbcfgsL != null && fbcfgsL.limit()>0) { for (int i = 0; i < fbcfgsL.limit(); i++) { - if( !X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(availableCaps, glProfile, absDevice, fbcfgsL.get(i), winattrmask, isMultisampleAvailable) ) { - if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (1): ("+x11Screen+","+capsChosen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); - } + final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL.get(i), winattrmask, isMultisampleAvailable); + if( null != caps ) { + availableCaps.add(caps); + } else if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (1): ("+x11Screen+","+capsChosen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); } } if(availableCaps.size() > 0) { @@ -318,10 +315,11 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } for (int i = 0; i < fbcfgsL.limit(); i++) { - if( !X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(availableCaps, glProfile, absDevice, fbcfgsL.get(i), winattrmask, isMultisampleAvailable) ) { - if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); - } + final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.GLXFBConfig2GLCapabilities(x11Device, glProfile, fbcfgsL.get(i), winattrmask, isMultisampleAvailable); + if( null != caps ) { + availableCaps.add(caps); + } else if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationFBConfig: FBConfig invalid (2): ("+x11Screen+"): fbcfg: "+toHexString(fbcfgsL.get(i))); } } } @@ -374,11 +372,11 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } GLProfile glProfile = capsChosen.getGLProfile(); - final int winattrmask = GLGraphicsConfigurationUtil.getWinAttributeBits(capsChosen.isOnscreen(), false /* pbuffer */, false); + final int winattrmask = GLGraphicsConfigurationUtil.getExclusiveWinAttributeBits(capsChosen.isOnscreen(), capsChosen.isFBO(), false /* pbuffer */, capsChosen.isBitmap()); List<GLCapabilitiesImmutable> availableCaps = new ArrayList<GLCapabilitiesImmutable>(); int recommendedIndex = -1; - AbstractGraphicsDevice absDevice = x11Screen.getDevice(); + X11GraphicsDevice absDevice = (X11GraphicsDevice) x11Screen.getDevice(); long display = absDevice.getHandle(); int screen = x11Screen.getIndex(); @@ -411,15 +409,15 @@ public class X11GLXGraphicsConfigurationFactory extends GLGraphicsConfigurationF } for (int i = 0; i < infos.length; i++) { - if( !X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities(availableCaps, glProfile, display, infos[i], winattrmask, isMultisampleAvailable) ) { - if(DEBUG) { - System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: XVisual invalid: ("+x11Screen+"): fbcfg: "+toHexString(infos[i].getVisualid())); - } - } else { + final GLCapabilitiesImmutable caps = X11GLXGraphicsConfiguration.XVisualInfo2GLCapabilities(absDevice, glProfile, infos[i], winattrmask, isMultisampleAvailable); + if( null != caps ) { + availableCaps.add(caps); // Attempt to find the visual chosenIndex by glXChooseVisual, if not translucent if (capsChosen.isBackgroundOpaque() && recommendedVis != null && recommendedVis.getVisualid() == infos[i].getVisualid()) { recommendedIndex = availableCaps.size() - 1; } + } else if(DEBUG) { + System.err.println("X11GLXGraphicsConfiguration.chooseGraphicsConfigurationXVisual: XVisual invalid: ("+x11Screen+"): fbcfg: "+toHexString(infos[i].getVisualid())); } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java index e1fe2f27e..bba2b3513 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java @@ -81,10 +81,11 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { } private void createPbuffer() { - X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration(); - AbstractGraphicsScreen aScreen = config.getScreen(); - AbstractGraphicsDevice aDevice = aScreen.getDevice(); - long display = aDevice.getHandle(); + final MutableSurface ms = (MutableSurface) getNativeSurface(); + final X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) ms.getGraphicsConfiguration(); + final AbstractGraphicsScreen aScreen = config.getScreen(); + final AbstractGraphicsDevice aDevice = aScreen.getDevice(); + final long display = aDevice.getHandle(); if (DEBUG) { System.out.println("Pbuffer config: " + config); @@ -94,8 +95,6 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { throw new GLException("Null display"); } - NativeSurface ns = getNativeSurface(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); if (chosenCaps.getPbufferRenderToTexture()) { @@ -111,9 +110,9 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { int[] iattributes = new int[7]; iattributes[niattribs++] = GLX.GLX_PBUFFER_WIDTH; - iattributes[niattribs++] = ns.getWidth(); + iattributes[niattribs++] = ms.getWidth(); iattributes[niattribs++] = GLX.GLX_PBUFFER_HEIGHT; - iattributes[niattribs++] = ns.getHeight(); + iattributes[niattribs++] = ms.getHeight(); iattributes[niattribs++] = GLX.GLX_LARGEST_PBUFFER; // exact iattributes[niattribs++] = 0; iattributes[niattribs++] = 0; @@ -125,7 +124,7 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { } // Set up instance variables - ((MutableSurface)ns).setSurfaceHandle(pbuffer); + ms.setSurfaceHandle(pbuffer); if (DEBUG) { System.err.println("Created pbuffer " + this); |