diff options
Diffstat (limited to 'src')
14 files changed, 982 insertions, 166 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/FBObject.java b/src/jogl/classes/com/jogamp/opengl/FBObject.java index 7d0fcfa38..6f2ac3e35 100644 --- a/src/jogl/classes/com/jogamp/opengl/FBObject.java +++ b/src/jogl/classes/com/jogamp/opengl/FBObject.java @@ -835,6 +835,8 @@ public class FBObject { checkPreGLError(gl); + if( 0 >= width ) { width = 1; } + if( 0 >= height ) { height = 1; } this.width = width; this.height = height; this.samples = samples <= maxSamples ? samples : maxSamples; @@ -941,7 +943,7 @@ public class FBObject { * @throws GLException in case of an error, i.e. size too big, etc .. */ public final void reset(GL gl, int newWidth, int newHeight, int newSamples, boolean resetSamplingSink) { - if(!initialized) { + if( !initialized ) { init(gl, newWidth, newHeight, newSamples); return; } @@ -949,10 +951,10 @@ public class FBObject { newSamples = newSamples <= maxSamples ? newSamples : maxSamples; // clamp if( newWidth != width || newHeight != height || newSamples != samples ) { - if(0>=newWidth) { newWidth = 1; } - if(0>=newHeight) { newHeight = 1; } - if(newWidth > 2 + maxTextureSize || newHeight> 2 + maxTextureSize || - newWidth > maxRenderbufferSize || newHeight> maxRenderbufferSize ) { + if( 0 >= newWidth ) { newWidth = 1; } + if( 0 >= newHeight ) { newHeight = 1; } + if( newWidth > 2 + maxTextureSize || newHeight > 2 + maxTextureSize || + newWidth > maxRenderbufferSize || newHeight > maxRenderbufferSize ) { throw new GLException("size "+width+"x"+height+" exceeds on of the maxima [texture "+maxTextureSize+", renderbuffer "+maxRenderbufferSize+"]"); } diff --git a/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java b/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java index 4a1a81bcb..7f5316fbd 100644 --- a/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java +++ b/src/jogl/classes/jogamp/opengl/GLBufferStateTracker.java @@ -91,6 +91,7 @@ public class GLBufferStateTracker { bindingMap.setKeyNotFoundValue(0xFFFFFFFF); // Start with known unbound targets for known keys + // setBoundBufferObject(GL2GL3.GL_VERTEX_ARRAY_BINDING, 0); // not using default VAO (removed in GL3 core) - only explicit setBoundBufferObject(GL.GL_ARRAY_BUFFER, 0); setBoundBufferObject(GL.GL_ELEMENT_ARRAY_BUFFER, 0); setBoundBufferObject(GL2.GL_PIXEL_PACK_BUFFER, 0); @@ -120,6 +121,7 @@ public class GLBufferStateTracker { boolean gotQueryTarget = true; int queryTarget = 0; switch (target) { + case GL2GL3.GL_VERTEX_ARRAY_BINDING: queryTarget = GL2GL3.GL_VERTEX_ARRAY_BINDING; break; case GL.GL_ARRAY_BUFFER: queryTarget = GL.GL_ARRAY_BUFFER_BINDING; break; case GL.GL_ELEMENT_ARRAY_BUFFER: queryTarget = GL.GL_ELEMENT_ARRAY_BUFFER_BINDING; break; case GL2.GL_PIXEL_PACK_BUFFER: queryTarget = GL2.GL_PIXEL_PACK_BUFFER_BINDING; break; diff --git a/src/jogl/classes/jogamp/opengl/GLContextImpl.java b/src/jogl/classes/jogamp/opengl/GLContextImpl.java index 0d8b193af..9f7c9cf57 100644 --- a/src/jogl/classes/jogamp/opengl/GLContextImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLContextImpl.java @@ -342,23 +342,24 @@ public abstract class GLContextImpl extends GLContext { @Override public final void destroy() { - if ( null == drawable ) { - throw new GLException("Drawable is null: "+toString()); - } if ( DEBUG_TRACE_SWITCH ) { + final long drawH = null != drawable ? drawable.getHandle() : 0; System.err.println(getThreadName() + ": GLContextImpl.destroy.0: obj " + toHexString(hashCode()) + ", ctx " + toHexString(contextHandle) + - ", surf "+toHexString(drawable.getHandle())+", isShared "+GLContextShareSet.isShared(this)+" - "+lock); + ", surf "+toHexString(drawH)+", isShared "+GLContextShareSet.isShared(this)+" - "+lock); } - if ( 0 != contextHandle ) { + if ( 0 != contextHandle ) { // isCreated() ? + if ( null == drawable ) { + throw new GLException("GLContext created but drawable is null: "+toString()); + } final int lockRes = drawable.lockSurface(); if ( NativeSurface.LOCK_SURFACE_NOT_READY >= lockRes ) { // this would be odd .. throw new GLException("Surface not ready to lock: "+drawable); } - Throwable drawableContextRealizedException = null; + Throwable associateDrawableException = null; try { if ( !drawable.isRealized() ) { - throw new GLException("Drawable not realized: "+toString()); + throw new GLException("GLContext created but drawable not realized: "+toString()); } // Must hold the lock around the destroy operation to make sure we // don't destroy the context while another thread renders to it. @@ -380,7 +381,7 @@ public abstract class GLContextImpl extends GLContext { try { associateDrawable(false); } catch (Throwable t) { - drawableContextRealizedException = t; + associateDrawableException = t; } if ( 0 != defaultVAO ) { int[] tmp = new int[] { defaultVAO }; @@ -410,8 +411,8 @@ public abstract class GLContextImpl extends GLContext { } finally { drawable.unlockSurface(); } - if(null != drawableContextRealizedException) { - throw new GLException("GLContext.destroy() during GLDrawableImpl.contextRealized(this, false)", drawableContextRealizedException); + if( null != associateDrawableException ) { + throw new GLException("GLContext.destroy() during associateDrawable(false)", associateDrawableException); } } resetStates(); @@ -601,6 +602,13 @@ public abstract class GLContextImpl extends GLContext { private final int makeCurrentWithinLock(int surfaceLockRes) throws GLException { if (!isCreated()) { + if( 0 >= drawable.getWidth() || 0 >= drawable.getHeight() ) { + if ( DEBUG_TRACE_SWITCH ) { + System.err.println(getThreadName() + ": Create GL context REJECTED (zero surface size) obj " + toHexString(hashCode()) + ", surf "+toHexString(drawable.getHandle())+" for " + getClass().getName()); + System.err.println(drawable.toString()); + } + return CONTEXT_NOT_CURRENT; + } if(DEBUG_GL) { // only impacts w/ createContextARB(..) additionalCtxCreationFlags |= GLContext.CTX_OPTION_DEBUG ; @@ -1782,6 +1790,10 @@ public abstract class GLContextImpl extends GLContext { public final GLStateTracker getGLStateTracker() { return glStateTracker; } + + public final boolean isDefaultVAO(int vao) { + return defaultVAO == vao; + } //--------------------------------------------------------------------------- // Helpers for context optimization where the last context is left diff --git a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java index ac10e2728..85f63b52c 100644 --- a/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLFBODrawableImpl.java @@ -335,16 +335,17 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { protected final void contextMadeCurrent(GLContext glc, boolean current) { final GL gl = glc.getGL(); if(current) { + if( !initialized ) { + throw new GLException("Not initialized: "+this); + } fbos[fboIBack].bind(gl); fboBound = true; - } else { - if(fboBound) { - swapFBOImpl(glc); - swapFBOImplPost(glc); - fboBound=false; - if(DEBUG_SWAP) { - System.err.println("Post FBO swap(@release): done"); - } + } else if( fboBound ) { + swapFBOImpl(glc); + swapFBOImplPost(glc); + fboBound=false; + if(DEBUG_SWAP) { + System.err.println("Post FBO swap(@release): done"); } } } @@ -353,17 +354,15 @@ public class GLFBODrawableImpl extends GLDrawableImpl implements GLFBODrawable { protected void swapBuffersImpl(boolean doubleBuffered) { final GLContext ctx = GLContext.getCurrent(); boolean doPostSwap = false; - if(null!=ctx && ctx.getGLDrawable()==this) { - if(fboBound) { - swapFBOImpl(ctx); - doPostSwap = true; - fboBound=false; - if(DEBUG_SWAP) { - System.err.println("Post FBO swap(@swap): done"); - } + if( null != ctx && ctx.getGLDrawable() == this && fboBound ) { + swapFBOImpl(ctx); + doPostSwap = true; + fboBound=false; + if(DEBUG_SWAP) { + System.err.println("Post FBO swap(@swap): done"); } } - if(null != swapBufferContext) { + if( null != swapBufferContext ) { swapBufferContext.swapBuffers(doubleBuffered); } if(doPostSwap) { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index a197bd51f..6cab369cf 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -622,7 +622,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl * Hence this method blocks the main-thread only for a short period of time. * </p> */ - class AttachNSOpenGLLayer implements Runnable { + class AttachGLLayerCmd implements Runnable { final OffscreenLayerSurface ols; final long ctx; final int shaderProgram; @@ -637,7 +637,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl /** Synchronized by instance's monitor */ boolean valid; - AttachNSOpenGLLayer(OffscreenLayerSurface ols, long ctx, int shaderProgram, long pfmt, long pbuffer, int texID, boolean isOpaque, int width, int height) { + AttachGLLayerCmd(OffscreenLayerSurface ols, long ctx, int shaderProgram, long pfmt, long pbuffer, int texID, boolean isOpaque, int width, int height) { this.ols = ols; this.ctx = ctx; this.shaderProgram = shaderProgram; @@ -651,6 +651,15 @@ public abstract class MacOSXCGLContext extends GLContextImpl this.nsOpenGLLayer = 0; } + public final String contentToString() { + return "valid "+valid+", size "+width+"x"+height+", ctx "+toHexString(ctx)+", opaque "+isOpaque+", texID "+texID+", pbuffer "+toHexString(pbuffer)+", nsOpenGLLayer "+toHexString(nsOpenGLLayer); + } + + @Override + public final String toString() { + return "AttachGLLayerCmd["+contentToString()+"]"; + } + @Override public void run() { synchronized(this) { @@ -693,14 +702,20 @@ public abstract class MacOSXCGLContext extends GLContextImpl } } } - AttachNSOpenGLLayer attachCALayerCmd = null; + AttachGLLayerCmd attachGLLayerCmd = null; - class DetachNSOpenGLLayer implements Runnable { - final AttachNSOpenGLLayer cmd; + class DetachGLLayerCmd implements Runnable { + final AttachGLLayerCmd cmd; - DetachNSOpenGLLayer(AttachNSOpenGLLayer cmd) { + DetachGLLayerCmd(AttachGLLayerCmd cmd) { this.cmd = cmd; } + + @Override + public final String toString() { + return "DetachGLLayerCmd["+cmd.contentToString()+"]"; + } + @Override public void run() { synchronized( cmd ) { @@ -734,7 +749,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(drawable.getNativeSurface(), true); if(DEBUG) { - System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable: "+bound+", ctx "+toHexString(contextHandle)+", hasBackingLayerHost "+(null!=backingLayerHost)); + System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable: "+bound+", ctx "+toHexString(contextHandle)+ + ", hasBackingLayerHost "+(null!=backingLayerHost)+", attachGLLayerCmd "+attachGLLayerCmd); // Thread.dumpStack(); } @@ -785,10 +801,13 @@ public abstract class MacOSXCGLContext extends GLContextImpl } // All CALayer lifecycle ops are deferred on main-thread - attachCALayerCmd = new AttachNSOpenGLLayer( + attachGLLayerCmd = new AttachGLLayerCmd( backingLayerHost, ctx, gl3ShaderProgramName, pixelFormat, pbufferHandle, texID, chosenCaps.isBackgroundOpaque(), lastWidth, lastHeight ); - OSXUtil.RunOnMainThread(false, attachCALayerCmd); + if(DEBUG) { + System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable(true): "+attachGLLayerCmd); + } + OSXUtil.RunOnMainThread(false, attachGLLayerCmd); } else { // -> null == backingLayerHost lastWidth = drawable.getWidth(); lastHeight = drawable.getHeight(); @@ -798,8 +817,11 @@ public abstract class MacOSXCGLContext extends GLContextImpl } } else { // -> !bound if( null != backingLayerHost ) { - final AttachNSOpenGLLayer cmd = attachCALayerCmd; - attachCALayerCmd = null; + final AttachGLLayerCmd cmd = attachGLLayerCmd; + attachGLLayerCmd = null; + if( null == cmd ) { + throw new GLException("Null attachGLLayerCmd: "+drawable); + } if( 0 != cmd.pbuffer ) { CGL.setContextPBuffer(contextHandle, 0); } @@ -808,7 +830,11 @@ public abstract class MacOSXCGLContext extends GLContextImpl cmd.valid = true; // skip pending creation } else { // All CALayer lifecycle ops are deferred on main-thread - OSXUtil.RunOnMainThread(false, new DetachNSOpenGLLayer(cmd)); + final DetachGLLayerCmd dCmd = new DetachGLLayerCmd(cmd); + if(DEBUG) { + System.err.println("MaxOSXCGLContext.NSOpenGLImpl.associateDrawable(false): "+dCmd); + } + OSXUtil.RunOnMainThread(false, dCmd); if( null != gl3ShaderProgram ) { gl3ShaderProgram.destroy(MacOSXCGLContext.this.gl.getGL3()); gl3ShaderProgram = null; @@ -903,7 +929,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean setSwapInterval(int interval) { - final AttachNSOpenGLLayer cmd = attachCALayerCmd; + final AttachGLLayerCmd cmd = attachGLLayerCmd; if(null != cmd) { synchronized(cmd) { if( cmd.valid && 0 != cmd.nsOpenGLLayer) { @@ -932,7 +958,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl @Override public boolean swapBuffers() { - final AttachNSOpenGLLayer cmd = attachCALayerCmd; + final AttachGLLayerCmd cmd = attachGLLayerCmd; if(null != cmd) { synchronized(cmd) { if( cmd.valid && 0 != cmd.nsOpenGLLayer) { diff --git a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java index a6c655915..de62747be 100644 --- a/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java +++ b/src/newt/classes/com/jogamp/newt/opengl/GLWindow.java @@ -40,7 +40,6 @@ import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; -import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.SurfaceUpdatedListener; import javax.media.nativewindow.util.InsetsImmutable; import javax.media.nativewindow.util.Point; @@ -472,17 +471,16 @@ public class GLWindow extends GLAutoDrawableBase implements GLAutoDrawable, Wind if( ( null != context ) ) { throw new InternalError("GLWindow.LifecycleHook.setVisiblePost: "+WindowImpl.getThreadName()+" - Null drawable, but valid context - "+GLWindow.this); } - final NativeWindow nw; - if (window.getWrappedWindow() != null) { - nw = NativeWindowFactory.getNativeWindow(window.getWrappedWindow(), window.getPrivateGraphicsConfiguration()); - } else { - nw = window; + final NativeSurface ns; + { + final NativeSurface wrapped_ns = window.getWrappedSurface(); + ns = null != wrapped_ns ? wrapped_ns : window; } - final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) nw.getGraphicsConfiguration().getChosenCapabilities(); + final GLCapabilitiesImmutable glCaps = (GLCapabilitiesImmutable) ns.getGraphicsConfiguration().getChosenCapabilities(); if(null==factory) { factory = GLDrawableFactory.getFactory(glCaps.getGLProfile()); } - drawable = (GLDrawableImpl) factory.createGLDrawable(nw); + drawable = (GLDrawableImpl) factory.createGLDrawable(ns); drawable.setRealized(true); if( !GLWindow.this.pushGLEventListenerState() ) { diff --git a/src/newt/classes/jogamp/newt/WindowImpl.java b/src/newt/classes/jogamp/newt/WindowImpl.java index 01a58a305..bfb450f68 100644 --- a/src/newt/classes/jogamp/newt/WindowImpl.java +++ b/src/newt/classes/jogamp/newt/WindowImpl.java @@ -1562,9 +1562,11 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer return old; } - /** If this Window actually wraps one from another toolkit such as - the AWT, this will return a non-null value. */ - public Object getWrappedWindow() { + /** + * If this Window actually wraps a {@link NativeSurface} from another instance or toolkit, + * it will return such reference. Otherwise returns null. + */ + public NativeSurface getWrappedSurface() { return null; } @@ -1598,7 +1600,7 @@ public abstract class WindowImpl implements Window, NEWTEventConsumer "\n, Visible "+isVisible()+", focus "+hasFocus()+ "\n, Undecorated "+undecorated+" ("+isUndecorated()+")"+ "\n, AlwaysOnTop "+alwaysOnTop+", Fullscreen "+fullscreen+ - "\n, WrappedWindow "+getWrappedWindow()+ + "\n, WrappedSurface "+getWrappedSurface()+ "\n, ChildWindows "+childWindows.size()); sb.append(", SurfaceUpdatedListeners num "+surfaceUpdatedHelper.size()+" ["); diff --git a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java index 17eb6a2fb..9a1632130 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java +++ b/src/newt/classes/jogamp/newt/driver/awt/AWTCanvas.java @@ -47,13 +47,15 @@ import javax.media.nativewindow.AbstractGraphicsScreen; import javax.media.nativewindow.CapabilitiesChooser; import javax.media.nativewindow.CapabilitiesImmutable; import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; +import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.VisualIDHolder; - import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; +import com.jogamp.nativewindow.awt.JAWTWindow; import com.jogamp.newt.Window; @SuppressWarnings("serial") @@ -61,17 +63,15 @@ public class AWTCanvas extends Canvas { private GraphicsDevice device; private GraphicsConfiguration chosen; private AWTGraphicsConfiguration awtConfig; - - private WindowDriver newtWindowImpl; + private volatile JAWTWindow jawtWindow=null; // the JAWTWindow presentation of this AWT Canvas, bound to the 'drawable' lifecycle private CapabilitiesChooser chooser=null; private CapabilitiesImmutable capabilities; private boolean displayConfigChanged=false; - public AWTCanvas(WindowDriver newtWindowImpl, CapabilitiesImmutable capabilities, CapabilitiesChooser chooser) { + public AWTCanvas(CapabilitiesImmutable capabilities, CapabilitiesChooser chooser) { super(); - this.newtWindowImpl = newtWindowImpl; if(null==capabilities) { throw new NativeWindowException("Capabilities null"); } @@ -89,7 +89,7 @@ public class AWTCanvas extends Canvas { */ @Override public void update(Graphics g) { - paint(g); + // paint(g); } /** Overridden to cause OpenGL rendering to be performed during @@ -99,7 +99,6 @@ public class AWTCanvas extends Canvas { */ @Override public void paint(Graphics g) { - newtWindowImpl.windowRepaint(0, 0, getWidth(), getHeight()); } public boolean hasDeviceChanged() { @@ -120,8 +119,7 @@ public class AWTCanvas extends Canvas { */ awtConfig = chooseGraphicsConfiguration(capabilities, capabilities, chooser, device); if(Window.DEBUG_IMPLEMENTATION) { - Exception e = new Exception("Info: Created Config: "+awtConfig); - e.printStackTrace(); + System.err.println(getThreadName()+": AWTCanvas.addNotify.0: Created Config: "+awtConfig); } if(null==awtConfig) { throw new NativeWindowException("Error: NULL AWTGraphicsConfiguration"); @@ -137,12 +135,31 @@ public class AWTCanvas extends Canvas { // after native peer is valid: Windows disableBackgroundErase(); + { + jawtWindow = (JAWTWindow) NativeWindowFactory.getNativeWindow(this, awtConfig); + // trigger initialization cycle + jawtWindow.lockSurface(); + jawtWindow.unlockSurface(); + } + GraphicsConfiguration gc = super.getGraphicsConfiguration(); if(null!=gc) { device = gc.getDevice(); } + if(Window.DEBUG_IMPLEMENTATION) { + System.err.println(getThreadName()+": AWTCanvas.addNotify.X"); + } } + public NativeWindow getNativeWindow() { + final JAWTWindow _jawtWindow = jawtWindow; + return (null != _jawtWindow) ? _jawtWindow : null; + } + + public boolean isOffscreenLayerSurfaceEnabled() { + return null != jawtWindow ? jawtWindow.isOffscreenLayerSurfaceEnabled() : false; + } + public void removeNotify() { try { dispose(); @@ -152,6 +169,13 @@ public class AWTCanvas extends Canvas { } private void dispose() { + if( null != jawtWindow ) { + jawtWindow.destroy(); + if(Window.DEBUG_IMPLEMENTATION) { + System.err.println(getThreadName()+": AWTCanvas.disposeJAWTWindowAndAWTDeviceOnEDT(): post JAWTWindow: "+jawtWindow); + } + jawtWindow=null; + } if(null != awtConfig) { AbstractGraphicsDevice adevice = awtConfig.getNativeGraphicsConfiguration().getScreen().getDevice(); String adeviceMsg=null; @@ -160,10 +184,12 @@ public class AWTCanvas extends Canvas { } boolean closed = adevice.close(); if(Window.DEBUG_IMPLEMENTATION) { - System.err.println("AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); + System.err.println(getThreadName()+": AWTCanvas.dispose(): closed GraphicsDevice: "+adeviceMsg+", result: "+closed); } } } + + private String getThreadName() { return Thread.currentThread().getName(); } /** * Overridden to choose a GraphicsConfiguration on a parent container's diff --git a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java index 0172309fb..c45a5ae3b 100644 --- a/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java +++ b/src/newt/classes/jogamp/newt/driver/awt/WindowDriver.java @@ -40,11 +40,15 @@ import java.awt.Dimension; import java.awt.Frame; import java.awt.Insets; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindow; import javax.media.nativewindow.NativeWindowException; import javax.media.nativewindow.util.Point; +import jogamp.nativewindow.awt.AWTMisc; import jogamp.newt.WindowImpl; +import com.jogamp.common.os.Platform; import com.jogamp.nativewindow.awt.AWTGraphicsConfiguration; import com.jogamp.nativewindow.awt.AWTGraphicsDevice; import com.jogamp.nativewindow.awt.AWTGraphicsScreen; @@ -70,25 +74,26 @@ public class WindowDriver extends WindowImpl { public WindowDriver(Container container) { super(); - this.container = container; + this.awtContainer = container; if(container instanceof Frame) { - frame = (Frame) container; + awtFrame = (Frame) container; } } private boolean owningFrame; - private Container container = null; - private Frame frame = null; // same instance as container, just for impl. convenience - private AWTCanvas canvas; + private Container awtContainer = null; + /** same instance as container, just for impl. convenience */ + private Frame awtFrame = null; + private AWTCanvas awtCanvas; protected void requestFocusImpl(boolean reparented) { - container.requestFocus(); + awtContainer.requestFocus(); } @Override protected void setTitleImpl(final String title) { - if (frame != null) { - frame.setTitle(title); + if (awtFrame != null) { + awtFrame.setTitle(title); } } @@ -97,58 +102,66 @@ public class WindowDriver extends WindowImpl { throw new RuntimeException("Window parenting not supported in AWT, use AWTWindow(Frame) cstr for wrapping instead"); } - if(null==container) { - frame = new Frame(); - container = frame; + if(null==awtContainer) { + awtFrame = new Frame(); + awtContainer = awtFrame; owningFrame=true; } else { owningFrame=false; - defineSize(container.getWidth(), container.getHeight()); - definePosition(container.getX(), container.getY()); + defineSize(awtContainer.getWidth(), awtContainer.getHeight()); + definePosition(awtContainer.getX(), awtContainer.getY()); } - if(null!=frame) { - frame.setTitle(getTitle()); + if(null!=awtFrame) { + awtFrame.setTitle(getTitle()); } - container.setLayout(new BorderLayout()); + awtContainer.setLayout(new BorderLayout()); - canvas = new AWTCanvas(this, capsRequested, WindowDriver.this.capabilitiesChooser); + if( null == awtCanvas ) { + awtCanvas = new AWTCanvas(capsRequested, WindowDriver.this.capabilitiesChooser); - // canvas.addComponentListener(listener); - container.add(canvas, BorderLayout.CENTER); + // canvas.addComponentListener(listener); + awtContainer.add(awtCanvas, BorderLayout.CENTER); - // via EDT .. - new AWTMouseAdapter(this).addTo(canvas); // fwd all AWT Mouse events to here - new AWTKeyAdapter(this).addTo(canvas); // fwd all AWT Key events to here + // via EDT .. + new AWTMouseAdapter(this).addTo(awtCanvas); // fwd all AWT Mouse events to here + new AWTKeyAdapter(this).addTo(awtCanvas); // fwd all AWT Key events to here - // direct w/o EDT - new AWTWindowAdapter(new LocalWindowListener(), this).addTo(canvas); // fwd all AWT Window events to here + // direct w/o EDT + new AWTWindowAdapter(new LocalWindowListener(), this).addTo(awtCanvas); // fwd all AWT Window events to here + } reconfigureWindowImpl(getX(), getY(), getWidth(), getHeight(), getReconfigureFlags(FLAG_CHANGE_VISIBILITY | FLAG_CHANGE_DECORATION, true)); // throws exception if failed .. - setWindowHandle(1); // just a marker .. + final NativeWindow nw = awtCanvas.getNativeWindow(); + if( null != nw ) { + setGraphicsConfiguration( awtCanvas.getAWTGraphicsConfiguration() ); + setWindowHandle( nw.getWindowHandle() ); + } } protected void closeNativeImpl() { - setWindowHandle(0); // just a marker .. - if(null!=container) { - container.setVisible(false); - container.remove(canvas); - container.setEnabled(false); - canvas.setEnabled(false); + setWindowHandle(0); + if(null!=awtContainer) { + awtContainer.setVisible(false); + awtContainer.remove(awtCanvas); + awtContainer.setEnabled(false); + awtCanvas.setEnabled(false); } - if(owningFrame && null!=frame) { - frame.dispose(); + if(owningFrame && null!=awtFrame) { + awtFrame.dispose(); owningFrame=false; - frame = null; } + awtCanvas = null; + awtFrame = null; + awtContainer = null; } @Override public boolean hasDeviceChanged() { - boolean res = canvas.hasDeviceChanged(); + boolean res = awtCanvas.hasDeviceChanged(); if(res) { - final AWTGraphicsConfiguration cfg = canvas.getAWTGraphicsConfiguration(); + final AWTGraphicsConfiguration cfg = awtCanvas.getAWTGraphicsConfiguration(); if (null == cfg) { throw new NativeWindowException("Error Device change null GraphicsConfiguration: "+this); } @@ -164,17 +177,54 @@ public class WindowDriver extends WindowImpl { } protected void updateInsetsImpl(javax.media.nativewindow.util.Insets insets) { - Insets contInsets = container.getInsets(); + Insets contInsets = awtContainer.getInsets(); insets.setLeftWidth(contInsets.left); insets.setRightWidth(contInsets.right); insets.setTopHeight(contInsets.top); insets.setBottomHeight(contInsets.bottom); } + private void setCanvasSizeImpl(int width, int height) { + final Dimension szClient = new Dimension(width, height); + final java.awt.Window awtWindow = AWTMisc.getWindow(awtCanvas); + final Container c= null != awtWindow ? awtWindow : awtContainer; + awtCanvas.setMinimumSize(szClient); + awtCanvas.setPreferredSize(szClient); + if(DEBUG_IMPLEMENTATION) { + final Insets insets = c.getInsets(); + final Dimension szContainer = new Dimension(width + insets.left + insets.right, + height + insets.top + insets.bottom); + System.err.println(getThreadName()+": AWTWindow setCanvasSize: szClient "+szClient+", szCont "+szContainer+", insets "+insets); + } + awtCanvas.setSize(szClient); + awtCanvas.invalidate(); + if(null != awtWindow) { + awtWindow.pack(); + } else { + awtContainer.validate(); + } + } + private void setFrameSizeImpl(int width, int height) { + final Insets insets = awtContainer.getInsets(); + final Dimension szContainer = new Dimension(width + insets.left + insets.right, + height + insets.top + insets.bottom); + if(DEBUG_IMPLEMENTATION) { + final Dimension szClient = new Dimension(width, height); + System.err.println(getThreadName()+": AWTWindow setFrameSize: szClient "+szClient+", szCont "+szContainer+", insets "+insets); + } + awtContainer.setSize(szContainer); + awtCanvas.invalidate(); + awtContainer.validate(); + } + protected boolean reconfigureWindowImpl(int x, int y, int width, int height, int flags) { - if(0 != ( FLAG_CHANGE_DECORATION & flags) && null!=frame) { - if(!container.isDisplayable()) { - frame.setUndecorated(isUndecorated()); + if(DEBUG_IMPLEMENTATION) { + System.err.println("AWTWindow reconfig: "+x+"/"+y+" "+width+"x"+height+", "+ + getReconfigureFlagsAsString(null, flags)); + } + if(0 != ( FLAG_CHANGE_DECORATION & flags) && null!=awtFrame) { + if(!awtContainer.isDisplayable()) { + awtFrame.setUndecorated(isUndecorated()); } else { if(DEBUG_IMPLEMENTATION) { System.err.println(getThreadName()+": AWTWindow can't undecorate already created frame"); @@ -182,32 +232,31 @@ public class WindowDriver extends WindowImpl { } } - final Dimension szClient = new Dimension(width, height); - canvas.setMinimumSize(szClient); - canvas.setPreferredSize(szClient); - canvas.setSize(szClient); - if(DEBUG_IMPLEMENTATION) { - final Insets insets = container.getInsets(); - final Dimension szContainer = new Dimension(width + insets.left + insets.right, - height + insets.top + insets.bottom); - System.err.println(getThreadName()+": AWTWindow new size: szClient "+szClient+", szCont "+szContainer+", insets "+insets); - } - if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { - if(null != frame) { - frame.pack(); + if( 0 != ( FLAG_IS_VISIBLE & flags) ) { + setCanvasSizeImpl(width, height); + awtContainer.setVisible( true ); + } else { + awtContainer.setVisible( false ); + } + } else if( awtCanvas.getWidth() != width || awtCanvas.getHeight() != height ) { + if( Platform.OSType.MACOS == Platform.getOSType() && awtCanvas.isOffscreenLayerSurfaceEnabled() ) { + setFrameSizeImpl(width, height); + } else { + setCanvasSizeImpl(width, height); } - container.validate(); - container.setVisible(0 != ( FLAG_IS_VISIBLE & flags)); } + defineSize(width, height); // we are on AWT-EDT .. change values immediately - container.setLocation(x, y); + if( awtContainer.getX() != x || awtContainer.getY() != y ) { + awtContainer.setLocation(x, y); + } if( 0 != ( FLAG_CHANGE_VISIBILITY & flags) ) { if( 0 != ( FLAG_IS_VISIBLE & flags ) ) { if( !hasDeviceChanged() ) { // oops ?? - final AWTGraphicsConfiguration cfg = canvas.getAWTGraphicsConfiguration(); + final AWTGraphicsConfiguration cfg = awtCanvas.getAWTGraphicsConfiguration(); if(null == cfg) { throw new NativeWindowException("Error: !hasDeviceChanged && null == GraphicsConfiguration: "+this); } @@ -215,39 +264,37 @@ public class WindowDriver extends WindowImpl { } } visibleChanged(false, 0 != ( FLAG_IS_VISIBLE & flags)); - } else { - container.invalidate(); - if(null != frame) { - frame.pack(); - } - container.validate(); } return true; } protected Point getLocationOnScreenImpl(int x, int y) { - java.awt.Point ap = canvas.getLocationOnScreen(); + java.awt.Point ap = awtCanvas.getLocationOnScreen(); ap.translate(x, y); return new Point((int)(ap.getX()+0.5),(int)(ap.getY()+0.5)); } @Override - public Object getWrappedWindow() { - return canvas; + public NativeSurface getWrappedSurface() { + return ( null != awtCanvas ) ? awtCanvas.getNativeWindow() : null; } class LocalWindowListener implements com.jogamp.newt.event.WindowListener { @Override public void windowMoved(com.jogamp.newt.event.WindowEvent e) { - if(null!=container) { - WindowDriver.this.positionChanged(false, container.getX(), container.getY()); + if(null!=awtContainer) { + WindowDriver.this.positionChanged(false, awtContainer.getX(), awtContainer.getY()); } } @Override public void windowResized(com.jogamp.newt.event.WindowEvent e) { - if(null!=canvas) { - WindowDriver.this.sizeChanged(false, canvas.getWidth(), canvas.getHeight(), false); + if(null!=awtCanvas) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window Resized: "+awtCanvas); + } + WindowDriver.this.sizeChanged(false, awtCanvas.getWidth(), awtCanvas.getHeight(), true); + WindowDriver.this.windowRepaint(false, 0, 0, getWidth(), getHeight()); } } @Override @@ -268,7 +315,12 @@ public class WindowDriver extends WindowImpl { } @Override public void windowRepaint(WindowUpdateEvent e) { - WindowDriver.this.windowRepaint(false, 0, 0, getWidth(), getHeight()); + if(null!=awtCanvas) { + if(DEBUG_IMPLEMENTATION) { + System.err.println("Window Repaint: "+awtCanvas); + } + WindowDriver.this.windowRepaint(false, 0, 0, getWidth(), getHeight()); + } } } } diff --git a/src/test-native/displayMultiple02_mch.c b/src/test-native/displayMultiple02_mch.c new file mode 100644 index 000000000..c2ab25fbb --- /dev/null +++ b/src/test-native/displayMultiple02_mch.c @@ -0,0 +1,130 @@ +/** + * compile with: gcc -o displayMultiple02 displayMultiple02.c -lX11 -lGL + */ + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <GL/glx.h> +#include <GL/gl.h> + +static void testOrder(int reverseDestroyOrder, const char * msg); + +static int useXLockDisplay = 0; + +int main(int nargs, char **vargs) { + int arg=1; + while(arg<nargs) { + if(0 == strcmp(vargs[arg], "-xlock")) { + useXLockDisplay = 1; + } + arg++; + } + fprintf(stderr, "-xlock (XLockDisplay): %d\n", useXLockDisplay); + + if( useXLockDisplay ) { + XInitThreads(); + } + testOrder(0, "Normal order"); + testOrder(1, "Reverse order"); + return 0; +} + +static void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx); +static void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height); + +static void XLOCKDISPLAY(Display *dpy) { + if( useXLockDisplay ) { + XLockDisplay(dpy); + } +} +static void XUNLOCKDISPLAY(Display *dpy) { + if( useXLockDisplay ) { + XUnlockDisplay(dpy); + } +} + +void testOrder(int reverseDestroyOrder, const char * msg) { + int major, minor; + Display *disp1; + Window win1; + GLXContext ctx1; + + fprintf(stderr, "%s: Create #1\n", msg); + disp1 = XOpenDisplay(NULL); + XLOCKDISPLAY(disp1); + createGLWin(disp1, 200, 200, &win1, &ctx1); + useGL(disp1, win1, ctx1, 200, 200); + XUNLOCKDISPLAY(disp1); + + if(reverseDestroyOrder) { + fprintf(stderr, "%s: Destroy #1.0\n", msg); + XLOCKDISPLAY(disp1); + fprintf(stderr, "%s: Destroy #1.1\n", msg); + glXMakeCurrent(disp1, 0, 0); + fprintf(stderr, "%s: Destroy #1.2\n", msg); + glXDestroyContext(disp1, ctx1); + fprintf(stderr, "%s: Destroy #1.3\n", msg); + XUNLOCKDISPLAY(disp1); + fprintf(stderr, "%s: Destroy #1.4\n", msg); + XCloseDisplay(disp1); + fprintf(stderr, "%s: Destroy #1.X\n", msg); + } else { + fprintf(stderr, "%s: Destroy #1.0\n", msg); + XLOCKDISPLAY(disp1); + glXMakeCurrent(disp1, 0, 0); + glXDestroyContext(disp1, ctx1); + XUNLOCKDISPLAY(disp1); + XCloseDisplay(disp1); + fprintf(stderr, "%s: Destroy #1.X\n", msg); + } + + fprintf(stderr, "%s: Success - no bug\n", msg); +} + +/* attributes for a double buffered visual in RGBA format with at least + * 4 bits per color and a 16 bit depth buffer */ +static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_DEPTH_SIZE, 16, + None }; + +void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx) +{ + int screen = DefaultScreen(dpy); + XVisualInfo *vi = glXChooseVisual(dpy, screen, attrListDbl); + Colormap cmap; + XSetWindowAttributes attr; + + /* create a GLX context */ + *rCtx = glXCreateContext(dpy, vi, 0, GL_TRUE); + /* create a color map */ + cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); + attr.colormap = cmap; + attr.border_pixel = 0; + + /* create a window in window mode*/ + attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + *rWin = XCreateWindow(dpy, RootWindow(dpy, vi->screen), + 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &attr); + + XMapRaised(dpy, *rWin); +} + +void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height) +{ + glXMakeCurrent(dpy, win, ctx); + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glXSwapBuffers(dpy, win); + glXMakeCurrent(dpy, 0, 0); +} + diff --git a/src/test-native/displayMultiple02_new_mch.c b/src/test-native/displayMultiple02_new_mch.c new file mode 100644 index 000000000..f64d41472 --- /dev/null +++ b/src/test-native/displayMultiple02_new_mch.c @@ -0,0 +1,199 @@ +/** + * compile with: gcc -o displayMultiple02 displayMultiple02.c -lX11 -lGL + */ + +#include <stdio.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <GL/glx.h> +#include <GL/gl.h> + +static void testOrder(int reverseDestroyOrder, const char * msg); + +static int useXLockDisplay = 0; + +int main(int nargs, char **vargs) { + int arg=1; + while(arg<nargs) { + if(0 == strcmp(vargs[arg], "-xlock")) { + useXLockDisplay = 1; + } + arg++; + } + fprintf(stderr, "-xlock (XLockDisplay): %d\n", useXLockDisplay); + + if( useXLockDisplay ) { + XInitThreads(); + } + testOrder(0, "Normal order"); + testOrder(1, "Reverse order"); + return 0; +} + +static void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx); +static void createGLWinNew(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx); +static void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height); + +static void XLOCKDISPLAY(Display *dpy) { + if( useXLockDisplay ) { + XLockDisplay(dpy); + } +} +static void XUNLOCKDISPLAY(Display *dpy) { + if( useXLockDisplay ) { + XUnlockDisplay(dpy); + } +} + +void testOrder(int reverseDestroyOrder, const char * msg) { + int major, minor; + Display *disp1; + Window win1; + GLXContext ctx1; + + Display *disp2; + Window win2; + GLXContext ctx2; + + fprintf(stderr, "%s: Create #1\n", msg); + disp1 = XOpenDisplay(NULL); + XLOCKDISPLAY(disp1); + createGLWinNew(disp1, 200, 200, &win1, &ctx1); + useGL(disp1, win1, ctx1, 200, 200); + XUNLOCKDISPLAY(disp1); + + fprintf(stderr, "%s: Create #2\n", msg); + disp2 = XOpenDisplay(NULL); + XLOCKDISPLAY(disp2); + createGLWinNew(disp2, 300, 300, &win2, &ctx2); + useGL(disp2, win2, ctx2, 300, 300); + XUNLOCKDISPLAY(disp2); + + if(reverseDestroyOrder) { + fprintf(stderr, "%s: Destroy #2.0\n", msg); + XLOCKDISPLAY(disp2); + glXMakeCurrent(disp2, 0, 0); + glXDestroyContext(disp2, ctx2); + XUNLOCKDISPLAY(disp2); + XCloseDisplay(disp2); + fprintf(stderr, "%s: Destroy #2.X\n", msg); + + fprintf(stderr, "%s: Destroy #1.0\n", msg); + XLOCKDISPLAY(disp1); + fprintf(stderr, "%s: Destroy #1.1\n", msg); + glXMakeCurrent(disp1, 0, 0); + fprintf(stderr, "%s: Destroy #1.2\n", msg); + glXDestroyContext(disp1, ctx1); + fprintf(stderr, "%s: Destroy #1.3\n", msg); + XUNLOCKDISPLAY(disp1); + fprintf(stderr, "%s: Destroy #1.4\n", msg); + XCloseDisplay(disp1); + fprintf(stderr, "%s: Destroy #1.X\n", msg); + } else { + fprintf(stderr, "%s: Destroy #1.0\n", msg); + XLOCKDISPLAY(disp1); + glXMakeCurrent(disp1, 0, 0); + glXDestroyContext(disp1, ctx1); + XUNLOCKDISPLAY(disp1); + XCloseDisplay(disp1); + fprintf(stderr, "%s: Destroy #1.X\n", msg); + + fprintf(stderr, "%s: Destroy #2.0\n", msg); + XLOCKDISPLAY(disp2); + fprintf(stderr, "%s: Destroy #2.1\n", msg); + glXMakeCurrent(disp2, 0, 0); + fprintf(stderr, "%s: Destroy #2.2\n", msg); + glXDestroyContext(disp2, ctx2); + fprintf(stderr, "%s: Destroy #2.3\n", msg); + XUNLOCKDISPLAY(disp2); + fprintf(stderr, "%s: Destroy #2.4\n", msg); + XCloseDisplay(disp2); + fprintf(stderr, "%s: Destroy #2.X\n", msg); + } + + fprintf(stderr, "%s: Success - no bug\n", msg); +} + +/* attributes for a double buffered visual in RGBA format with at least + * 4 bits per color and a 16 bit depth buffer */ +static int attrListDbl[] = { GLX_RGBA, GLX_DOUBLEBUFFER, + GLX_RED_SIZE, 4, + GLX_GREEN_SIZE, 4, + GLX_BLUE_SIZE, 4, + GLX_DEPTH_SIZE, 16, + None }; +static int attrListDblNew[] = { GLX_DRAWABLE_TYPE, GLX_WINDOW_BIT, + GLX_RENDER_TYPE, GLX_RGBA_BIT, + GLX_DOUBLEBUFFER, True, + GLX_BUFFER_SIZE, 24, + GLX_DEPTH_SIZE, 24, + None }; + +void createGLWin(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx) +{ + int screen = DefaultScreen(dpy); + XVisualInfo *vi = glXChooseVisual(dpy, screen, attrListDbl); + Colormap cmap; + XSetWindowAttributes attr; + + /* create a GLX context */ + *rCtx = glXCreateContext(dpy, vi, 0, GL_TRUE); + /* create a color map */ + cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); + attr.colormap = cmap; + attr.border_pixel = 0; + + /* create a window in window mode*/ + attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + *rWin = XCreateWindow(dpy, RootWindow(dpy, vi->screen), + 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &attr); + + XMapRaised(dpy, *rWin); +} + +void createGLWinNew(Display *dpy, int width, int height, Window *rWin, GLXContext *rCtx) +{ + int screen = DefaultScreen(dpy); + Colormap cmap; + XSetWindowAttributes attr; + + // create configs + int nelements; + GLXFBConfig *fbconfigs = glXChooseFBConfig(dpy,screen,attrListDblNew,&nelements ); + + // get visual + XVisualInfo *vi = glXGetVisualFromFBConfig(dpy,*fbconfigs); + + /* create a GLX context */ + *rCtx = glXCreateNewContext(dpy, *fbconfigs, GLX_RGBA_TYPE, 0, GL_TRUE); + + /* create a color map */ + cmap = XCreateColormap(dpy, RootWindow(dpy, vi->screen), vi->visual, AllocNone); + attr.colormap = cmap; + attr.border_pixel = 0; + + /* create a window in window mode*/ + attr.event_mask = ExposureMask | KeyPressMask | ButtonPressMask | + StructureNotifyMask; + *rWin = XCreateWindow(dpy, RootWindow(dpy, vi->screen), + 0, 0, width, height, 0, vi->depth, InputOutput, vi->visual, + CWBorderPixel | CWColormap | CWEventMask, &attr); + + XMapRaised(dpy, *rWin); +} + +void useGL(Display *dpy, Window win, GLXContext ctx, int width, int height) +{ + glXMakeCurrent(dpy, win, ctx); + glShadeModel(GL_SMOOTH); + glClearColor(0.0f, 0.0f, 0.0f, 0.0f); + glClearDepth(1.0f); + glViewport(0, 0, width, height); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glXSwapBuffers(dpy, win); + glXMakeCurrent(dpy, 0, 0); +} + diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug692GL3VAO.java b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug692GL3VAO.java new file mode 100644 index 000000000..95944cd98 --- /dev/null +++ b/src/test/com/jogamp/opengl/test/junit/jogl/acore/TestBug692GL3VAO.java @@ -0,0 +1,352 @@ +/**
+ * Copyright 2013 JogAmp Community. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without modification, are
+ * permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice, this list of
+ * conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice, this list
+ * of conditions and the following disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+ * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
+ * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * The views and conclusions contained in the software and documentation are those of the
+ * authors and should not be interpreted as representing official policies, either expressed
+ * or implied, of JogAmp Community.
+ */
+package com.jogamp.opengl.test.junit.jogl.acore;
+
+import java.io.IOException;
+import java.nio.FloatBuffer;
+import java.nio.ShortBuffer;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.media.opengl.DebugGL3;
+import javax.media.opengl.GL3;
+import javax.media.opengl.GLAutoDrawable;
+import javax.media.opengl.GLCapabilities;
+import javax.media.opengl.GLEventListener;
+import javax.media.opengl.GLException;
+import javax.media.opengl.GLProfile;
+
+import junit.framework.Assert;
+
+import org.junit.Test;
+
+import com.jogamp.common.nio.Buffers;
+import com.jogamp.newt.opengl.GLWindow;
+import com.jogamp.opengl.test.junit.util.MiscUtils;
+import com.jogamp.opengl.test.junit.util.QuitAdapter;
+import com.jogamp.opengl.test.junit.util.UITestCase;
+import com.jogamp.opengl.util.Animator;
+import com.jogamp.opengl.util.GLBuffers;
+
+/**
+ * Test Vertex Array Object (VAO) Usage.
+ * <p>
+ * testGL3() tests VAO alone, i.e. w/o VBO enable/disabling.
+ * </p>
+ * <p>
+ * testGL3bc() tests VAO and VBO while alternating between both methods.
+ * </p>
+ */
+public class TestBug692GL3VAO extends UITestCase {
+ static long duration = 500; // ms
+
+ static class GL3VAODemo implements GLEventListener {
+ /** Different modes of displaying the geometry */
+ public enum Mode {
+ /** Traditional one without using VAO */
+ NON_VAO {
+ @Override
+ void display(GL3VAODemo t, GL3 gl) {
+ t.displayNonVAO(gl);
+ }
+ },
+
+ /** Using VAOs throws [incorrectly as of JOGL 2.0rc11] a GLException */
+ VAO_NORMAL {
+ @Override
+ void display(GL3VAODemo t, GL3 gl) {
+ t.displayVAONormal(gl);
+ }
+ };
+
+ abstract void display(GL3VAODemo t, GL3 gl);
+ }
+
+ private final Mode[] allModes;
+ private Mode currentMode;
+ private int currentModeIdx;
+
+ public GL3VAODemo(Mode[] modes) {
+ allModes = modes;
+ currentMode = allModes[0];
+ currentModeIdx = 0;
+ }
+
+ private final static float[] vertexData = new float[]{
+ 0.0f, 0.75f, 0.0f, 1,0,0,
+ -0.5f, -0.75f, 0.0f, 0,1,0,
+ 0.9f, -0.75f, 0.0f, 0,0,1
+ };
+
+ private int ibo = -1;
+ private int vbo = -1;
+ private int vertID = -1;
+ private int fragID = -1;
+ private int progID = -1;
+
+ private int vaoNormal = -1;
+
+ private static int createShader(final GL3 gl, int type,
+ final String[] srcLines){
+ int shaderID = gl.glCreateShader(type);
+ assert shaderID > 0;
+ int[] lengths = new int[srcLines.length];
+ for (int i = 0; i < srcLines.length; i++) {
+ lengths[i] = srcLines[i].length();
+ }
+ gl.glShaderSource(shaderID, srcLines.length, srcLines, lengths, 0);
+ gl.glCompileShader(shaderID);
+ return shaderID;
+ }
+
+ private void initBuffers(GL3 gl) {
+ // IDs for 2 buffers
+ int[] buffArray = new int[2];
+ gl.glGenBuffers(buffArray.length, buffArray, 0);
+ vbo = buffArray[0];
+ assert vbo > 0;
+
+ // Bind buffer and upload data
+ gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo);
+ FloatBuffer buffer = GLBuffers.newDirectFloatBuffer(vertexData);
+ assert buffer.remaining() == vertexData.length;
+ gl.glBufferData(GL3.GL_ARRAY_BUFFER, vertexData.length * Buffers.SIZEOF_FLOAT,
+ buffer, GL3.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
+
+ // Buffer with the 3 indices required for one triangle
+ ibo = buffArray[1];
+ assert ibo > 0;
+ final short[] indices = new short[]{0, 1, 2};
+ ShortBuffer shortBuffer = GLBuffers.newDirectShortBuffer(indices);
+ assert shortBuffer.remaining() == indices.length;
+ gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, ibo);
+ gl.glBufferData(GL3.GL_ELEMENT_ARRAY_BUFFER,indices.length*Buffers.SIZEOF_SHORT,
+ shortBuffer, GL3.GL_STATIC_DRAW);
+ gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+ private void initShaders(GL3 gl) {
+ final String[] vertSrc = new String[]{
+ "#version 150 core\n",
+ "in vec4 vPosition;\n",
+ "in vec4 vColor;\n",
+ "out vec4 pColor;\n",
+ "void main() {\n",
+ " pColor = vColor;\n",
+ " gl_Position = vPosition;\n",
+ "}\n"
+ };
+ vertID = createShader(gl, GL3.GL_VERTEX_SHADER, vertSrc);
+
+ final String[] fragSrc = new String[]{
+ "#version 150 core\n",
+ "in vec4 pColor;\n",
+ "void main() {\n",
+ " gl_FragColor = pColor;\n",
+ "}\n"
+ };
+ fragID = createShader(gl, GL3.GL_FRAGMENT_SHADER, fragSrc);
+
+ // We're done with the compiler
+ gl.glReleaseShaderCompiler();
+
+ progID = gl.glCreateProgram();
+ assert progID > 0;
+ gl.glAttachShader(progID, vertID);
+ gl.glAttachShader(progID, fragID);
+ gl.glLinkProgram(progID);
+ gl.glValidateProgram(progID);
+ }
+
+ private int initVAO(GL3 gl) {
+ int[] buff = new int[1];
+ gl.glGenVertexArrays(1, buff, 0);
+ int vao = buff[0];
+ Assert.assertTrue("Invalid VAO: "+vao, vao > 0);
+
+
+ gl.glUseProgram(progID);
+ final int posLoc = gl.glGetAttribLocation(progID, "vPosition");
+ final int colorLoc = gl.glGetAttribLocation(progID, "vColor");
+ gl.glUseProgram(0);
+
+ gl.glBindVertexArray(vao);
+ gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo);
+ gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, ibo);
+
+ gl.glEnableVertexAttribArray(posLoc);
+ gl.glEnableVertexAttribArray(colorLoc);
+
+ final int stride = 6 * Buffers.SIZEOF_FLOAT;
+ final int cOff = 3 * Buffers.SIZEOF_FLOAT;
+ gl.glVertexAttribPointer(posLoc, 3, GL3.GL_FLOAT, false, stride, 0L);
+ gl.glVertexAttribPointer(colorLoc,3, GL3.GL_FLOAT, false, stride, cOff);
+
+ gl.glBindVertexArray(0);
+ return vao;
+ }
+
+ @Override
+ public void init(GLAutoDrawable drawable) {
+ drawable.setGL(new DebugGL3(drawable.getGL().getGL3()));
+
+ final GL3 gl = drawable.getGL().getGL3();
+ gl.glEnable(GL3.GL_DEPTH_TEST);
+ gl.glDisable(GL3.GL_CULL_FACE);
+ initBuffers(gl);
+ initShaders(gl);
+
+ vaoNormal = initVAO(gl);
+
+ gl.setSwapInterval(1);
+ }
+
+ @Override
+ public void dispose(GLAutoDrawable drawable) {
+ final GL3 gl = drawable.getGL().getGL3();
+ gl.glDeleteBuffers(2, new int[]{vbo, ibo}, 0);
+ gl.glDetachShader(progID, fragID);
+ gl.glDetachShader(progID, vertID);
+ gl.glDeleteProgram(progID);
+ gl.glDeleteShader(fragID);
+ gl.glDeleteShader(vertID);
+ }
+
+ private void displayNonVAO(final GL3 gl) {
+ final int posLoc = gl.glGetAttribLocation(progID, "vPosition");
+ final int colorLoc = gl.glGetAttribLocation(progID, "vColor");
+ gl.glEnableVertexAttribArray(posLoc);
+ gl.glEnableVertexAttribArray(colorLoc);
+
+ gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, vbo);
+ final int stride = 6 * Buffers.SIZEOF_FLOAT;
+ final int cOff = 3 * Buffers.SIZEOF_FLOAT;
+ gl.glVertexAttribPointer(posLoc, 3, GL3.GL_FLOAT, false, stride, 0L);
+ gl.glVertexAttribPointer(colorLoc,3, GL3.GL_FLOAT, false, stride, cOff);
+ gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, ibo);
+ gl.glDrawElements(GL3.GL_TRIANGLES, 3, GL3.GL_UNSIGNED_SHORT, 0L);
+
+ gl.glDisableVertexAttribArray(posLoc);
+ gl.glDisableVertexAttribArray(colorLoc);
+ gl.glBindBuffer(GL3.GL_ARRAY_BUFFER, 0);
+ gl.glBindBuffer(GL3.GL_ELEMENT_ARRAY_BUFFER, 0);
+ }
+
+ private void displayVAONormal(final GL3 gl) {
+ try {
+ gl.glBindVertexArray(vaoNormal);
+ gl.glDrawElements(GL3.GL_TRIANGLES, 3, GL3.GL_UNSIGNED_SHORT, 0L);
+ gl.glBindVertexArray(0);
+ } catch (GLException ex) {
+ Logger.getLogger(TestBug692GL3VAO.class.getName()).log(Level.SEVERE,null,ex);
+ }
+ }
+
+ @Override
+ public void display(GLAutoDrawable drawable) {
+ final GL3 gl = drawable.getGL().getGL3();
+ float color = ((float) currentMode.ordinal() + 1) / (Mode.values().length + 2);
+ gl.glClearColor(color, color, color, 0);
+ gl.glClear(GL3.GL_COLOR_BUFFER_BIT | GL3.GL_DEPTH_BUFFER_BIT);
+ gl.glUseProgram(progID);
+ final Mode newMode;
+ {
+ currentModeIdx = ( currentModeIdx + 1 ) % allModes.length;
+ newMode = allModes[ currentModeIdx ];
+ }
+ if (newMode != currentMode) {
+ currentMode = newMode;
+ System.out.println("Display mode: " + currentMode);
+ }
+ currentMode.display(this, gl);
+ gl.glUseProgram(0);
+ }
+
+ @Override
+ public void reshape(GLAutoDrawable drawable, int x, int y, int w, int h) {
+ }
+ }
+
+ private void testImpl(GLProfile profile, GL3VAODemo.Mode[] modes) throws InterruptedException {
+ final GLCapabilities capabilities = new GLCapabilities(profile);
+ final GLWindow glWindow = GLWindow.create(capabilities);
+ glWindow.setSize(512, 512);
+
+ Animator anim = new Animator(glWindow);
+
+ QuitAdapter quitAdapter = new QuitAdapter();
+ glWindow.addKeyListener(quitAdapter);
+ glWindow.addWindowListener(quitAdapter);
+
+ final GL3VAODemo vaoTest = new GL3VAODemo(modes);
+ glWindow.addGLEventListener(vaoTest);
+ glWindow.setVisible(true);
+ anim.start();
+
+ final long t0 = System.currentTimeMillis();
+ long t1 = t0;
+ while(!quitAdapter.shouldQuit() && t1-t0<duration) {
+ Thread.sleep(100);
+ t1 = System.currentTimeMillis();
+ }
+
+ anim.stop();
+ glWindow.destroy();
+ }
+
+ //@Test
+ public void testGL3() throws GLException, InterruptedException {
+ if( ! GLProfile.isAvailable(GLProfile.GL3) ) {
+ System.err.println("GL3 n/a");
+ return;
+ }
+ GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.VAO_NORMAL };
+ testImpl(GLProfile.get(GLProfile.GL3), modes);
+ }
+
+ @Test
+ public void testGL3bc() throws GLException, InterruptedException {
+ if( ! GLProfile.isAvailable(GLProfile.GL3bc) ) {
+ System.err.println("GL3bc n/a");
+ return;
+ }
+ GL3VAODemo.Mode[] modes = new GL3VAODemo.Mode[] { GL3VAODemo.Mode.VAO_NORMAL, GL3VAODemo.Mode.NON_VAO };
+ testImpl(GLProfile.get(GLProfile.GL3bc), modes);
+ }
+
+ public static void main(String args[]) throws IOException {
+ for(int i=0; i<args.length; i++) {
+ if(args[i].equals("-time")) {
+ duration = MiscUtils.atoi(args[++i], (int)duration);
+ }
+ }
+ String tstname = TestBug692GL3VAO.class.getName();
+ org.junit.runner.JUnitCore.main(tstname);
+ }
+
+}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java index 5e523c780..9bbbbce05 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/GearsES2.java @@ -270,7 +270,7 @@ public class GearsES2 implements GLEventListener { public void display(GLAutoDrawable drawable) { GLAnimatorControl anim = drawable.getAnimator(); if( verbose && ( null == anim || !anim.isAnimating() ) ) { - System.err.println(Thread.currentThread()+" GearsES2.display"+drawable.getWidth()+"x"+drawable.getHeight()+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle())); + System.err.println(Thread.currentThread()+" GearsES2.display "+drawable.getWidth()+"x"+drawable.getHeight()+", swapInterval "+swapInterval+", drawable 0x"+Long.toHexString(drawable.getHandle())); } // Turn the gears' teeth if(doRotate) { diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java index cc20cc27e..0b907d5ee 100644 --- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java +++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/gl2/newt/TestGearsNewtAWTWrapper.java @@ -34,6 +34,7 @@ import javax.media.opengl.*; import com.jogamp.opengl.util.Animator; import com.jogamp.opengl.test.junit.util.AWTRobotUtil; +import com.jogamp.opengl.test.junit.util.MiscUtils; import com.jogamp.opengl.test.junit.util.UITestCase; import com.jogamp.opengl.test.junit.util.QuitAdapter; import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2; @@ -49,6 +50,9 @@ import org.junit.Test; public class TestGearsNewtAWTWrapper extends UITestCase { static GLProfile glp; static int width, height; + static boolean useAnimator = true; + static boolean doResizeTest = true; + static long duration = 500; // ms @BeforeClass public static void initClass() { @@ -73,39 +77,50 @@ public class TestGearsNewtAWTWrapper extends UITestCase { glWindow.addGLEventListener(new GearsES2(1)); - Animator animator = new Animator(glWindow); + Animator animator = useAnimator ? new Animator(glWindow) : null; QuitAdapter quitAdapter = new QuitAdapter(); glWindow.addKeyListener(new TraceKeyAdapter(quitAdapter)); glWindow.addWindowListener(new TraceWindowAdapter(quitAdapter)); + if( useAnimator ) { + animator.start(); + } + int div = 3; glWindow.setSize(width/div, height/div); glWindow.setVisible(true); - glWindow.display(); - Assert.assertTrue("Size not reached: Expected "+(width/div)+"x"+(height/div)+", Is "+glWindow.getWidth()+"x"+glWindow.getHeight(), - AWTRobotUtil.waitForSize(glWindow, width/div, height/div)); - - div = 2; - glWindow.setSize(width/div, height/div); - glWindow.display(); - Assert.assertTrue("Size not reached: Expected "+(width/div)+"x"+(height/div)+", Is "+glWindow.getWidth()+"x"+glWindow.getHeight(), - AWTRobotUtil.waitForSize(glWindow, width/div, height/div)); - - div = 1; - glWindow.setSize(width/div, height/div); - glWindow.display(); - Assert.assertTrue("Size not reached: Expected "+(width/div)+"x"+(height/div)+", Is "+glWindow.getWidth()+"x"+glWindow.getHeight(), - AWTRobotUtil.waitForSize(glWindow, width/div, height/div)); - - animator.setUpdateFPSFrames(1, null); - animator.start(); + if( doResizeTest ) { + glWindow.display(); + Assert.assertTrue("Size not reached: Expected "+(width/div)+"x"+(height/div)+", Is "+glWindow.getWidth()+"x"+glWindow.getHeight(), + AWTRobotUtil.waitForSize(glWindow, width/div, height/div)); + Thread.sleep(600); + + div = 2; + glWindow.setSize(width/div, height/div); + glWindow.display(); + Assert.assertTrue("Size not reached: Expected "+(width/div)+"x"+(height/div)+", Is "+glWindow.getWidth()+"x"+glWindow.getHeight(), + AWTRobotUtil.waitForSize(glWindow, width/div, height/div)); + Thread.sleep(600); + + div = 1; + glWindow.setSize(width/div, height/div); + glWindow.display(); + Assert.assertTrue("Size not reached: Expected "+(width/div)+"x"+(height/div)+", Is "+glWindow.getWidth()+"x"+glWindow.getHeight(), + AWTRobotUtil.waitForSize(glWindow, width/div, height/div)); + Thread.sleep(600); + } - while(!quitAdapter.shouldQuit() && animator.isAnimating() && animator.getTotalFPSDuration()<duration) { + final long t0 = System.currentTimeMillis(); + long t1 = t0; + while(!quitAdapter.shouldQuit() && t1-t0<duration) { Thread.sleep(100); + t1 = System.currentTimeMillis(); } - animator.stop(); + if( useAnimator ) { + animator.stop(); + } glWindow.destroy(); } @@ -115,17 +130,18 @@ public class TestGearsNewtAWTWrapper extends UITestCase { runTestGL(caps); } - static long duration = 500; // ms - public static void main(String args[]) { for(int i=0; i<args.length; i++) { if(args[i].equals("-time")) { i++; - try { - duration = Integer.parseInt(args[i]); - } catch (Exception ex) { ex.printStackTrace(); } + duration = MiscUtils.atol(args[i], duration); + } else if(args[i].equals("-noanim")) { + useAnimator = false; + } else if(args[i].equals("-noresize")) { + doResizeTest = false; } } + System.err.println("useAnimator "+useAnimator); org.junit.runner.JUnitCore.main(TestGearsNewtAWTWrapper.class.getName()); } } |