diff options
Diffstat (limited to 'src/jogl')
53 files changed, 1430 insertions, 639 deletions
diff --git a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java index 93b75e70b..26d299663 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AWTAnimatorImpl.java @@ -164,7 +164,7 @@ class AWTAnimatorImpl implements AnimatorBase.AnimatorImpl { } }; - public boolean skipWaitForCompletion(Thread thread) { - return ((Thread.currentThread() == thread) || EventQueue.isDispatchThread()); + public boolean blockUntilDone(Thread thread) { + return ((Thread.currentThread() != thread) && !EventQueue.isDispatchThread()); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/Animator.java b/src/jogl/classes/com/jogamp/opengl/util/Animator.java index 16aac957a..a9023886d 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/Animator.java +++ b/src/jogl/classes/com/jogamp/opengl/util/Animator.java @@ -59,7 +59,9 @@ import javax.media.opengl.GLAutoDrawable; */ public class Animator extends AnimatorBase { - + /** timeout in milliseconds, 15 frames @ 60Hz = 240ms, limiting {@link #finishLifecycleAction(Condition)} */ + private static final long TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION = 15*16; + protected ThreadGroup threadGroup; private Runnable runnable; private boolean runAsFastAsPossible; @@ -241,16 +243,20 @@ public class Animator extends AnimatorBase { // dependencies on the Animator's internal thread. Currently we // use a couple of heuristics to determine whether we should do // the blocking wait(). - boolean doWait = !impl.skipWaitForCompletion(animThread); - if (doWait) { - while (condition.result()) { - try { - wait(); - } catch (InterruptedException ie) { } - } + long remaining = impl.blockUntilDone(animThread) ? TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION : 0; + while (remaining>0 && condition.result()) { + long td = System.currentTimeMillis(); + try { + wait(remaining); + } catch (InterruptedException ie) { } + remaining -= (System.currentTimeMillis() - td) ; } if(DEBUG) { - System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished - waited " + doWait + + if(remaining<0) { + System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): ++++++ timeout reached ++++++ "); + } + System.err.println("finishLifecycleAction(" + condition.getClass().getName() + "): finished "+ + "- waited " + (TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION-remaining) + "/" + TO_WAIT_FOR_FINISH_LIFECYCLE_ACTION + ", started: " + isStartedImpl() +", animating: " + isAnimatingImpl() + ", paused: " + isPausedImpl() + ", drawables " + drawables.size()); } diff --git a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java index e84a9bf78..9bea27f45 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java +++ b/src/jogl/classes/com/jogamp/opengl/util/AnimatorBase.java @@ -56,7 +56,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { public interface AnimatorImpl { void display(ArrayList<GLAutoDrawable> drawables, boolean ignoreExceptions, boolean printExceptions); - boolean skipWaitForCompletion(Thread thread); + boolean blockUntilDone(Thread thread); } protected ArrayList<GLAutoDrawable> drawables = new ArrayList<GLAutoDrawable>(); @@ -101,7 +101,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { if(paused) { resume(); } - if(!impl.skipWaitForCompletion(animThread)) { + if(impl.blockUntilDone(animThread)) { while(isStarted() && !isPaused() && !isAnimating()) { try { wait(); @@ -123,7 +123,7 @@ public abstract class AnimatorBase implements GLAnimatorControl { if(paused) { resume(); } - if(!impl.skipWaitForCompletion(animThread)) { + if(impl.blockUntilDone(animThread)) { while(isStarted() && drawablesEmpty && isAnimating()) { try { wait(); diff --git a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java index bad268f70..23b0845ee 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java +++ b/src/jogl/classes/com/jogamp/opengl/util/DefaultAnimatorImpl.java @@ -60,7 +60,7 @@ class DefaultAnimatorImpl implements AnimatorBase.AnimatorImpl { } } - public boolean skipWaitForCompletion(Thread thread) { - return (Thread.currentThread() == thread); + public boolean blockUntilDone(Thread thread) { + return (Thread.currentThread() != thread); } } diff --git a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java index f2e742cda..62441d8b8 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java +++ b/src/jogl/classes/com/jogamp/opengl/util/GLBuffers.java @@ -491,6 +491,19 @@ public class GLBuffers extends Buffers { return sizeof(gl, tmp, elements * esize, width, height, depth, pack); } + + public static final int getNextPowerOf2(int number) { + if (((number-1) & number) == 0) { + //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 + return number; + } + int power = 0; + while (number > 0) { + number = number>>1; + power++; + } + return (1<<power); + } //---------------------------------------------------------------------- // Conversion routines diff --git a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java index b6df365ba..7f3aa8a39 100644 --- a/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java +++ b/src/jogl/classes/com/jogamp/opengl/util/texture/Texture.java @@ -1055,9 +1055,7 @@ public class Texture { // Helper routines for disabling certain codepaths private static boolean haveNPOT(GL gl) { - return (!disableNPOT && - ( gl.isGLES2() || - gl.isExtensionAvailable("GL_ARB_texture_non_power_of_two") ) ); + return !disableNPOT && gl.isNPOTTextureAvailable(); } private static boolean haveTexRect(GL gl) { diff --git a/src/jogl/classes/javax/media/opengl/GLBase.java b/src/jogl/classes/javax/media/opengl/GLBase.java index f93d443e0..534e449bc 100644 --- a/src/jogl/classes/javax/media/opengl/GLBase.java +++ b/src/jogl/classes/javax/media/opengl/GLBase.java @@ -294,6 +294,17 @@ public interface GLBase { */ public boolean isExtensionAvailable(String glExtensionName); + /** + * Returns true if the GL context supports non power of two (NPOT) textures, + * otherwise false. + * <p> + * NPOT textures are supported in OpenGL >= 3, GLES2 or if the + * 'GL_ARB_texture_non_power_of_two' extension is available. + * </p> + * @return + */ + public boolean isNPOTTextureAvailable(); + /** Provides a platform-independent way to specify the minimum swap interval for buffer swaps. An argument of 0 disables sync-to-vertical-refresh completely, while an argument of 1 diff --git a/src/jogl/classes/javax/media/opengl/GLContext.java b/src/jogl/classes/javax/media/opengl/GLContext.java index 9d99a32ff..31125af59 100644 --- a/src/jogl/classes/javax/media/opengl/GLContext.java +++ b/src/jogl/classes/javax/media/opengl/GLContext.java @@ -45,6 +45,7 @@ import java.security.AccessControlContext; import java.security.AccessController; import java.util.HashMap; import java.util.HashSet; + import javax.media.nativewindow.AbstractGraphicsDevice; import com.jogamp.common.util.IntObjectHashMap; @@ -767,12 +768,12 @@ public abstract class GLContext { /** * @see #getDeviceVersionAvailableKey(javax.media.nativewindow.AbstractGraphicsDevice, int, int) */ - protected static /*final*/ HashMap/*<DeviceVersionAvailableKey, Integer>*/ deviceVersionAvailable = new HashMap(); + protected static /*final*/ HashMap<String, Integer> deviceVersionAvailable = new HashMap<String, Integer>(); /** * @see #getUniqueDeviceString(javax.media.nativewindow.AbstractGraphicsDevice) */ - private static /*final*/ HashSet/*<UniqueDeviceString>*/ deviceVersionsAvailableSet = new HashSet(); + private static /*final*/ HashSet<String> deviceVersionsAvailableSet = new HashSet<String>(); protected static String getDeviceVersionAvailableKey(AbstractGraphicsDevice device, int major, int profile) { return device.getUniqueID() + "-" + toHexString(compose8bit(major, profile, 0, 0)); @@ -824,7 +825,7 @@ public abstract class GLContext { String key = getDeviceVersionAvailableKey(device, reqMajor, profile); Integer val = new Integer(compose8bit(resMajor, resMinor, resCtp, 0)); synchronized(deviceVersionAvailable) { - val = (Integer) deviceVersionAvailable.put( key, val ); + val = deviceVersionAvailable.put( key, val ); } return val; } @@ -833,7 +834,7 @@ public abstract class GLContext { String key = getDeviceVersionAvailableKey(device, reqMajor, profile); Integer val; synchronized(deviceVersionAvailable) { - val = (Integer) deviceVersionAvailable.get( key ); + val = deviceVersionAvailable.get( key ); } return val; } @@ -875,29 +876,29 @@ public abstract class GLContext { return null != getAvailableGLVersion(device, major, profile); } - public static boolean isGLES1Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); - } + public static boolean isGLES1Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 1, GLContext.CTX_PROFILE_ES); + } - public static boolean isGLES2Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); - } + public static boolean isGLES2Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 2, GLContext.CTX_PROFILE_ES); + } - public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); - } + public static boolean isGL4bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_COMPAT); + } - public static boolean isGL4Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); - } + public static boolean isGL4Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 4, CTX_PROFILE_CORE); + } - public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); - } + public static boolean isGL3bcAvailable(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_COMPAT); + } - public static boolean isGL3Available(AbstractGraphicsDevice device) { - return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); - } + public static boolean isGL3Available(AbstractGraphicsDevice device) { + return isGLVersionAvailable(device, 3, CTX_PROFILE_CORE); + } public static boolean isGL2Available(AbstractGraphicsDevice device) { return isGLVersionAvailable(device, 2, CTX_PROFILE_COMPAT); @@ -941,6 +942,10 @@ public abstract class GLContext { return sb.toString(); } + // + // internal string utils + // + protected static String toString(int val, boolean hex) { if(hex) { return "0x" + Integer.toHexString(val); diff --git a/src/jogl/classes/javax/media/opengl/GLDrawable.java b/src/jogl/classes/javax/media/opengl/GLDrawable.java index f4cd77059..2b86a04ba 100644 --- a/src/jogl/classes/javax/media/opengl/GLDrawable.java +++ b/src/jogl/classes/javax/media/opengl/GLDrawable.java @@ -158,6 +158,12 @@ public interface GLDrawable { */ public GLProfile getGLProfile(); + /** + * Returns the underlying native surface which surface handle + * represents this OpenGL drawable's native resource. + * + * @see #getHandle() + */ public NativeSurface getNativeSurface(); /** diff --git a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java index 92be62b4d..94fb250ce 100644 --- a/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java +++ b/src/jogl/classes/javax/media/opengl/awt/GLJPanel.java @@ -83,6 +83,8 @@ import javax.media.opengl.GLProfile; import javax.media.opengl.GLRunnable; import javax.media.opengl.Threading; import com.jogamp.opengl.util.FBObject; +import com.jogamp.opengl.util.GLBuffers; + import jogamp.opengl.Debug; import jogamp.opengl.GLContextImpl; import jogamp.opengl.GLDrawableFactoryImpl; @@ -776,17 +778,7 @@ public class GLJPanel extends JPanel implements AWTGLAutoDrawable, WindowClosing if (number == 0) { return 2; } - - if (((number-1) & number) == 0) { - //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 - return number; - } - int power = 0; - while (number > 0) { - number = number>>1; - power++; - } - return (1<<power); + return GLBuffers.getNextPowerOf2(number); } private int getGLInteger(GL gl, int which) { diff --git a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java index 2fa708404..bc9a93042 100644 --- a/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java +++ b/src/jogl/classes/jogamp/graph/curve/text/GlyphString.java @@ -79,7 +79,7 @@ public class GlyphString { * @param shape is not null, add all {@link GlyphShape}'s {@link Outline} to this instance. * @param vertexFactory vertex impl factory {@link Factory} * @param font the target {@link Font} - * @param size font size + * @param fontSize font size * @param str string text * @return the created {@link GlyphString} instance */ diff --git a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java index 96d62fbb3..27569d210 100644 --- a/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java +++ b/src/jogl/classes/jogamp/opengl/FPSCounterImpl.java @@ -28,6 +28,8 @@ package jogamp.opengl; import java.io.PrintStream; +import java.util.concurrent.TimeUnit; + import javax.media.opengl.FPSCounter; /** @@ -55,7 +57,7 @@ public class FPSCounterImpl implements FPSCounter { public final synchronized void tickFPS() { fpsTotalFrames++; if(fpsUpdateFramesInterval>0 && fpsTotalFrames%fpsUpdateFramesInterval == 0) { - final long now = System.currentTimeMillis(); + final long now = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); fpsLastPeriod = now - fpsLastUpdateTime; fpsLastPeriod = Math.max(fpsLastPeriod, 1); // div 0 fpsLast = ( (float)fpsUpdateFramesInterval * 1000f ) / ( (float) fpsLastPeriod ) ; @@ -96,7 +98,7 @@ public class FPSCounterImpl implements FPSCounter { } public final synchronized void resetFPSCounter() { - fpsStartTime = System.currentTimeMillis(); // overwrite startTime to real init one + fpsStartTime = TimeUnit.NANOSECONDS.toMillis(System.nanoTime()); // overwrite startTime to real init one fpsLastUpdateTime = fpsStartTime; fpsLastPeriod = 0; fpsTotalFrames = 0; diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java index 704f71457..068190cb2 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableFactoryImpl.java @@ -40,9 +40,26 @@ package jogamp.opengl; -import java.nio.*; -import javax.media.nativewindow.*; -import javax.media.opengl.*; +import java.nio.Buffer; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.OffscreenLayerSurface; +import javax.media.nativewindow.ProxySurface; +import javax.media.nativewindow.SurfaceChangeable; +import javax.media.opengl.GLCapabilities; +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.GLPbuffer; +import javax.media.opengl.GLProfile; +import javax.media.opengl.Threading; + +import jogamp.nativewindow.MutableGraphicsConfiguration; import com.jogamp.common.util.VersionNumber; @@ -103,24 +120,43 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { if (target == null) { throw new IllegalArgumentException("Null target"); } - AbstractGraphicsConfiguration config = target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MutableGraphicsConfiguration config = (MutableGraphicsConfiguration) target.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); AbstractGraphicsDevice adevice = config.getScreen().getDevice(); GLDrawable result = null; adevice.lock(); try { - if(caps.isOnscreen()) { - if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target); + if(chosenCaps.isOnscreen()) { + // onscreen + final OffscreenLayerSurface ols = NativeWindowFactory.getOffscreenLayerSurface(target, true); + if(null == ols) { + // traditional onscreen + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable: "+target); + } + result = createOnscreenDrawableImpl(target); + } else { + // layered surface -> offscreen/PBuffer + final GLCapabilities chosenCapsMod = (GLCapabilities) chosenCaps.cloneMutable(); + chosenCapsMod.setOnscreen(false); + chosenCapsMod.setPBuffer(canCreateGLPbuffer(adevice)); + config.setChosenCapabilities(chosenCapsMod); + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OnscreenDrawable -> Offscreen-Layer: "+target); + } + if( ! ( target instanceof SurfaceChangeable ) ) { + throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen layered surface: "+target); + } + result = createOffscreenDrawableImpl(target); } - result = createOnscreenDrawableImpl(target); } else { + // offscreen + if(DEBUG) { + System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+chosenCaps.isPBuffer()+"): "+target); + } if( ! ( target instanceof SurfaceChangeable ) ) { throw new IllegalArgumentException("Passed NativeSurface must implement SurfaceChangeable for offscreen: "+target); } - if(DEBUG) { - System.err.println("GLDrawableFactoryImpl.createGLDrawable -> OffScreenDrawable (PBuffer: "+caps.isPBuffer()+"): "+target); - } result = createOffscreenDrawableImpl(target); } } finally { @@ -287,15 +323,6 @@ public abstract class GLDrawableFactoryImpl extends GLDrawableFactory { // GLDrawableFactoryImpl details // - protected void maybeDoSingleThreadedWorkaround(Runnable action) { - if (Threading.isSingleThreaded() && - !Threading.isOpenGLThread()) { - Threading.invokeOnOpenGLThread(action); - } else { - action.run(); - } - } - /** * Returns the sole GLDrawableFactoryImpl instance. * diff --git a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java index 58c9aaaa6..6b6ce9f9e 100644 --- a/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java +++ b/src/jogl/classes/jogamp/opengl/GLDrawableImpl.java @@ -125,7 +125,10 @@ public abstract class GLDrawableImpl implements GLDrawable { return surface; } + /** called with locked surface @ setRealized(false) */ protected void destroyHandle() {} + + /** called with locked surface @ setRealized(true) or @ lockSurface(..) when surface changed */ protected void updateHandle() {} public long getHandle() { diff --git a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java index 318d00637..6e2b7b744 100644 --- a/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java +++ b/src/jogl/classes/jogamp/opengl/GLGraphicsConfigurationUtil.java @@ -29,6 +29,7 @@ package jogamp.opengl; import java.util.ArrayList; + import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; @@ -86,6 +87,7 @@ public class GLGraphicsConfigurationUtil { return getWinAttributeBits(caps.isOnscreen(), caps.isPBuffer()); } + @SuppressWarnings({ "rawtypes", "unchecked" }) public static final boolean addGLCapabilitiesPermutations(ArrayList capsBucket, GLCapabilitiesImmutable temp, int winattrbits) { int preSize = capsBucket.size(); if( 0 != ( WINDOW_BIT & winattrbits ) ) { @@ -138,7 +140,7 @@ public class GLGraphicsConfigurationUtil { if( capsRequested.getDoubleBuffered() || capsRequested.isOnscreen() || !capsRequested.isPBuffer()) { // fix caps .. GLCapabilities caps2 = (GLCapabilities) capsRequested.cloneMutable(); - caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN + caps2.setDoubleBuffered(false); // FIXME DBLBUFOFFSCRN - we don't need to be single buffered .. caps2.setOnscreen(false); caps2.setPBuffer(true); return caps2; diff --git a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java index 2c396e265..5979056f3 100644 --- a/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java +++ b/src/jogl/classes/jogamp/opengl/SharedResourceRunner.java @@ -61,7 +61,7 @@ public class SharedResourceRunner implements Runnable { String initConnection = null; String releaseConnection = null; - HashSet devicesTried = new HashSet(); + HashSet<String> devicesTried = new HashSet<String>(); private boolean getDeviceTried(String connection) { synchronized (devicesTried) { @@ -86,7 +86,7 @@ public class SharedResourceRunner implements Runnable { public SharedResourceRunner.Resource getOrCreateShared(AbstractGraphicsDevice device) { SharedResourceRunner.Resource sr = null; if(null != device) { - String connection = device.getConnection(); + final String connection = device.getConnection(); sr = impl.mapGet(connection); if (null == sr && !getDeviceTried(connection)) { addDeviceTried(connection); diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java index a9cc40335..de10b066d 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawable.java @@ -197,6 +197,16 @@ public abstract class EGLDrawable extends GLDrawableImpl { } } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { + if(DEBUG) { + System.err.println("eglSwapBuffers failed:"); + Thread.dumpStack(); + } + } + } + public int getWidth() { int[] tmp = new int[1]; if (!EGL.eglQuerySurface(eglDisplay, eglSurface, EGL.EGL_WIDTH, tmp, 0)) { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java index 79d96bdb6..decc74258 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLDrawableFactory.java @@ -268,7 +268,7 @@ public class EGLDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device, GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { WrappedSurface ns = new WrappedSurface(EGLGraphicsConfigurationFactory.createOffscreenGraphicsConfiguration(device, capsChosen, capsRequested, chooser)); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java index 4fb3dca78..ea625fb27 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLGraphicsConfiguration.java @@ -38,15 +38,25 @@ package jogamp.opengl.egl; import java.nio.IntBuffer; import java.util.ArrayList; -import javax.media.nativewindow.*; -import javax.media.nativewindow.egl.*; -import javax.media.opengl.*; + +import javax.media.nativewindow.AbstractGraphicsDevice; +import javax.media.nativewindow.AbstractGraphicsScreen; +import javax.media.nativewindow.GraphicsConfigurationFactory; +import javax.media.nativewindow.egl.EGLGraphicsDevice; +import javax.media.opengl.DefaultGLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesChooser; +import javax.media.opengl.GLCapabilitiesImmutable; +import javax.media.opengl.GLException; +import javax.media.opengl.GLProfile; + +import jogamp.nativewindow.MutableGraphicsConfiguration; +import jogamp.opengl.Debug; +import jogamp.opengl.GLGraphicsConfigurationUtil; import com.jogamp.common.nio.Buffers; import com.jogamp.common.nio.PointerBuffer; -import jogamp.opengl.*; -public class EGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class EGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { protected static final boolean DEBUG = Debug.debug("GraphicsConfiguration"); public final long getNativeConfig() { diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java index 7d5e0448d..42f067b29 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLOnscreenDrawable.java @@ -55,15 +55,5 @@ public class EGLOnscreenDrawable extends EGLDrawable { protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { return EGL.eglCreateWindowSurface(eglDpy, eglNativeCfg, surfaceHandle, null); } - - protected void swapBuffersImpl() { - if(!EGL.eglSwapBuffers(eglDisplay, eglSurface)) { - if(DEBUG) { - System.err.println("eglSwapBuffers failed:"); - Thread.dumpStack(); - } - } - } - } diff --git a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java index 5fb32e6cd..be6c80c41 100644 --- a/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java +++ b/src/jogl/classes/jogamp/opengl/egl/EGLPbufferDrawable.java @@ -40,48 +40,40 @@ package jogamp.opengl.egl; +import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.SurfaceChangeable; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; -import jogamp.opengl.x11.glx.GLX; - public class EGLPbufferDrawable extends EGLDrawable { private int texFormat; protected static final boolean useTexture = false; // No yet .. protected EGLPbufferDrawable(EGLDrawableFactory factory, NativeSurface target) { super(factory, target); + setRealized(true); + } - // get choosen ones .. - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) - getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration().getChosenCapabilities(); + protected void destroyImpl() { + setRealized(false); + } + + protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { + final AbstractGraphicsConfiguration config = getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); if(useTexture) { - this.texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB ; + texFormat = caps.getAlphaBits() > 0 ? EGL.EGL_TEXTURE_RGBA : EGL.EGL_TEXTURE_RGB ; } else { - this.texFormat = EGL.EGL_NO_TEXTURE; + texFormat = EGL.EGL_NO_TEXTURE; } if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); + System.out.println("Pbuffer config: " + config); } - setRealized(true); - - if (DEBUG) { - System.out.println("Created pbuffer: " + this); - } - - } - - protected void destroyImpl() { - setRealized(false); - } - - protected long createSurface(long eglDpy, long eglNativeCfg, long surfaceHandle) { NativeSurface nw = getNativeSurface(); int[] attrs = EGLGraphicsConfiguration.CreatePBufferSurfaceAttribList(nw.getWidth(), nw.getHeight(), texFormat); long surf = EGL.eglCreatePbufferSurface(eglDpy, eglNativeCfg, attrs, 0); @@ -97,11 +89,5 @@ public class EGLPbufferDrawable extends EGLDrawable { public GLContext createContext(GLContext shareWith) { return new EGLPbufferContext(this, shareWith); } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java index 1fe47f60b..f5970fad9 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java @@ -45,7 +45,9 @@ import java.util.Map; import javax.media.nativewindow.AbstractGraphicsConfiguration; import javax.media.nativewindow.AbstractGraphicsDevice; -import javax.media.nativewindow.DefaultGraphicsConfiguration; +import javax.media.nativewindow.NativeSurface; +import javax.media.nativewindow.NativeWindowFactory; +import javax.media.nativewindow.OffscreenLayerSurface; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; @@ -63,7 +65,6 @@ import com.jogamp.common.util.VersionNumber; import com.jogamp.gluegen.runtime.ProcAddressTable; import com.jogamp.gluegen.runtime.opengl.GLProcAddressResolver; - public abstract class MacOSXCGLContext extends GLContextImpl { // Abstract interface for implementation of this context (either @@ -76,7 +77,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl boolean makeCurrent(long ctx); boolean release(long ctx); boolean setSwapInterval(int interval); - boolean swapBuffers(boolean isOnscreen); + boolean swapBuffers(); } /* package */ static final boolean isTigerOrLater; @@ -268,9 +269,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl } protected void swapBuffers() { - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable caps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - if(!impl.swapBuffers(caps.isOnscreen())) { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + if(!impl.swapBuffers()) { throw new GLException("Error swapping buffers: "+this); } } @@ -282,12 +282,6 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(!impl.setSwapInterval(interval)) { throw new GLException("Error set swap-interval: "+this); } - if ( isNSContext() ) { - CGL.setSwapInterval(contextHandle, interval); - } else { - int[] lval = new int[] { (int) interval } ; - CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); - } currentSwapInterval = interval ; } @@ -403,31 +397,44 @@ public abstract class MacOSXCGLContext extends GLContextImpl // NSOpenGLContext-based implementation class NSOpenGLImpl implements GLBackendImpl { + long nsOpenGLLayer = 0; + long nsOpenGLLayerPFmt = 0; + public boolean isNSContext() { return true; } public long create(long share, int ctp, int major, int minor) { long ctx = 0; - MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); + final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) MacOSXCGLContext.this.drawable; + final NativeSurface surface = drawable.getNativeSurface(); + final MacOSXCGLGraphicsConfiguration config = (MacOSXCGLGraphicsConfiguration) surface.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final OffscreenLayerSurface backingLayerHost = NativeWindowFactory.getOffscreenLayerSurface(surface, true); + final GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable) config.getChosenCapabilities(); long pixelFormat = MacOSXCGLGraphicsConfiguration.GLCapabilities2NSPixelFormat(chosenCaps, ctp, major, minor); if (pixelFormat == 0) { throw new GLException("Unable to allocate pixel format with requested GLCapabilities"); } config.setChosenPixelFormat(pixelFormat); + if(DEBUG) { + System.err.println("NS create OSX>=lion "+isLionOrLater); + 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(drawable.getNSViewHandle())); + // Thread.dumpStack(); + } try { int[] viewNotReady = new int[1]; // Try to allocate a context with this ctx = CGL.createContext(share, - drawable.getHandle(), + drawable.getNSViewHandle(), null!=backingLayerHost, pixelFormat, chosenCaps.isBackgroundOpaque(), viewNotReady, 0); if (0 == ctx) { - if (viewNotReady[0] == 1) { - if (DEBUG) { - System.err.println("!!! View not ready for " + getClass().getName()); - } - // View not ready at the window system level + if(DEBUG) { + System.err.println("NS create failed: viewNotReady: "+ (1 == viewNotReady[0])); } return 0; } @@ -439,22 +446,63 @@ public abstract class MacOSXCGLContext extends GLContextImpl if(DEBUG) { GLCapabilitiesImmutable caps0 = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(null, pixelFormat); - System.err.println("NS created(>=lion "+isLionOrLater+"): "+caps0); + System.err.println("NS create pixelformat2GLCaps: "+caps0); + } + GLCapabilitiesImmutable fixedCaps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); + fixedCaps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(fixedCaps, chosenCaps.isBackgroundOpaque()); + config.setChosenCapabilities(fixedCaps); + if(DEBUG) { + System.err.println("NS create fixedCaps: "+fixedCaps); } - GLCapabilitiesImmutable caps = MacOSXCGLGraphicsConfiguration.NSPixelFormat2GLCapabilities(chosenCaps.getGLProfile(), pixelFormat); - caps = GLGraphicsConfigurationUtil.fixOpaqueGLCapabilities(caps, chosenCaps.isBackgroundOpaque()); - config.setChosenCapabilities(caps); - if(caps.isPBuffer()) { + if(fixedCaps.isPBuffer()) { // Must now associate the pbuffer with our newly-created context CGL.setContextPBuffer(ctx, drawable.getHandle()); - } + } + // + // handled layered surface + // + 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(); + } + nsOpenGLLayer = CGL.createNSOpenGLLayer(ctx, nsOpenGLLayerPFmt, drawable.getHandle(), fixedCaps.isBackgroundOpaque(), texWidth, texHeight); + if (DEBUG) { + System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)); + } + backingLayerHost.attachSurfaceLayer(nsOpenGLLayer); + } } finally { - CGL.deletePixelFormat(pixelFormat); + if(0!=pixelFormat) { + CGL.deletePixelFormat(pixelFormat); + } } return ctx; } 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) { + throw new InternalError("XXX: "+ols); + } + CGL.releaseNSOpenGLLayer(nsOpenGLLayer); + ols.detachSurfaceLayer(nsOpenGLLayer); + CGL.deletePixelFormat(nsOpenGLLayerPFmt); + nsOpenGLLayerPFmt = 0; + nsOpenGLLayer = 0; + } return CGL.deleteContext(ctx, true); } @@ -472,14 +520,26 @@ public abstract class MacOSXCGLContext extends GLContextImpl } public boolean setSwapInterval(int interval) { - CGL.setSwapInterval(contextHandle, interval); + if(0 != nsOpenGLLayer) { + CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval); + } + CGL.setSwapInterval(contextHandle, interval); return true; } - public boolean swapBuffers(boolean isOnscreen) { - if(isOnscreen) { - return CGL.flushBuffer(contextHandle); - } - return true; + + public boolean swapBuffers() { + if(0 != nsOpenGLLayer) { + // sync w/ CALayer renderer - wait until next frame is required (v-sync) + CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, 16); // timeout 16ms -> 60Hz + } + if(CGL.flushBuffer(contextHandle)) { + if(0 != nsOpenGLLayer) { + // trigger CALayer to update + CGL.setNSOpenGLLayerNeedsDisplay(nsOpenGLLayer); + } + return true; + } + return false; } } @@ -547,11 +607,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl CGL.CGLSetParameter(contextHandle, CGL.kCGLCPSwapInterval, lval, 0); return true; } - public boolean swapBuffers(boolean isOnscreen) { - if(isOnscreen) { - return CGL.kCGLNoError == CGL.CGLFlushDrawable(contextHandle); - } - return true; + 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 5a35f661d..12d480fd1 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawable.java @@ -40,6 +40,11 @@ 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.GLDrawableFactory; import javax.media.opengl.GLException; @@ -87,18 +92,46 @@ public abstract class MacOSXCGLDrawable extends GLDrawableImpl { this.id = id; } } - + private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); + private boolean haveSetOpenGLMode = false; private GLBackendType openGLMode = GLBackendType.NSOPENGL; public MacOSXCGLDrawable(GLDrawableFactory factory, NativeSurface comp, boolean realized) { super(factory, comp, realized); - initOpenGLImpl(getOpenGLMode()); - } - + initOpenGLImpl(getOpenGLMode()); + } + protected void setRealizedImpl() { } + protected long getNSViewHandle() { + return GLBackendType.NSOPENGL == openGLMode ? getHandle() : null; + } + + protected void registerContext(MacOSXCGLContext ctx) { + // 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)); + } + } + 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(); + } + } + } + } + public GLDynamicLookupHelper getGLDynamicLookupHelper() { return getFactoryImpl().getGLDynamicLookupHelper(0); } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java index 5c726bc54..30917476e 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLDrawableFactory.java @@ -42,6 +42,7 @@ package jogamp.opengl.macosx.cgl; import java.nio.Buffer; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import javax.media.nativewindow.AbstractGraphicsConfiguration; @@ -52,6 +53,7 @@ import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.NativeWindowFactory; import javax.media.nativewindow.ProxySurface; import javax.media.nativewindow.macosx.MacOSXGraphicsDevice; +import javax.media.opengl.GL; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesChooser; import javax.media.opengl.GLCapabilitiesImmutable; @@ -113,18 +115,28 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { // private MacOSXCGLContext context; MacOSXGraphicsDevice device; boolean wasContextCreated; + boolean hasNPOTTextures; + boolean hasRECTTextures; + boolean hasAppletFloatPixels; - SharedResource(MacOSXGraphicsDevice device, boolean wasContextCreated + SharedResource(MacOSXGraphicsDevice device, boolean wasContextCreated, + boolean hasNPOTTextures, boolean hasRECTTextures, boolean hasAppletFloatPixels /* MacOSXCGLDrawable draw, MacOSXCGLContext ctx */) { // drawable = draw; // context = ctx; this.device = device; this.wasContextCreated = wasContextCreated; + this.hasNPOTTextures = hasNPOTTextures; + this.hasRECTTextures = hasRECTTextures; + this.hasAppletFloatPixels = hasAppletFloatPixels; } final MacOSXGraphicsDevice getDevice() { return device; } final boolean wasContextAvailable() { return wasContextCreated; } + final boolean isNPOTTextureAvailable() { return hasNPOTTextures; } + final boolean isRECTTextureAvailable() { return hasRECTTextures; } + final boolean isAppletFloatPixelsAvailable() { return hasAppletFloatPixels; } } - HashMap/*<connection, SharedResource>*/ sharedMap = new HashMap(); + HashMap<String, SharedResource> sharedMap = new HashMap<String, SharedResource>(); MacOSXGraphicsDevice defaultDevice; public final AbstractGraphicsDevice getDefaultDevice() { @@ -138,52 +150,78 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { return false; } - private boolean isOSXContextAvailable(AbstractGraphicsDevice sharedDevice) { - boolean madeCurrent = false; - GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); - if (null == glp) { - throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); - } - final GLCapabilities caps = new GLCapabilities(glp); - caps.setRedBits(5); caps.setGreenBits(5); caps.setBlueBits(5); caps.setAlphaBits(0); - caps.setDoubleBuffered(false); - caps.setOnscreen(false); - caps.setPBuffer(true); - final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) createGLDrawable( createOffscreenSurfaceImpl(sharedDevice, caps, caps, null, 64, 64) ); - if(null!=drawable) { - final GLContext context = drawable.createContext(null); - if (null != context) { - context.setSynchronized(true); - try { - context.makeCurrent(); // could cause exception - madeCurrent = context.isCurrent(); - } catch (GLException gle) { - if (DEBUG) { - System.err.println("MacOSXCGLDrawableFactory.createShared: INFO: makeCurrent failed"); - gle.printStackTrace(); - } - } finally { - context.destroy(); - } - } - drawable.destroy(); - } - return madeCurrent; + private HashSet<String> devicesTried = new HashSet<String>(); + + private boolean getDeviceTried(String connection) { + synchronized (devicesTried) { + return devicesTried.contains(connection); + } + } + private void addDeviceTried(String connection) { + synchronized (devicesTried) { + devicesTried.add(connection); + } + } + private void removeDeviceTried(String connection) { + synchronized (devicesTried) { + devicesTried.remove(connection); + } } /* package */ SharedResource getOrCreateOSXSharedResource(AbstractGraphicsDevice adevice) { - String connection = adevice.getConnection(); + final String connection = adevice.getConnection(); SharedResource sr; synchronized(sharedMap) { - sr = (SharedResource) sharedMap.get(connection); + sr = sharedMap.get(connection); } - if(null==sr) { + if(null==sr && !getDeviceTried(connection)) { + addDeviceTried(connection); final MacOSXGraphicsDevice sharedDevice = new MacOSXGraphicsDevice(adevice.getUnitID()); - final boolean madeCurrent = isOSXContextAvailable(sharedDevice); - sr = new SharedResource(sharedDevice, madeCurrent); + boolean madeCurrent = false; + boolean hasNPOTTextures = false; + boolean hasRECTTextures = false; + boolean hasAppletFloatPixels = false; + { + GLProfile glp = GLProfile.get(sharedDevice, GLProfile.GL_PROFILE_LIST_MIN_DESKTOP); + if (null == glp) { + throw new GLException("Couldn't get default GLProfile for device: "+sharedDevice); + } + final GLCapabilities caps = new GLCapabilities(glp); + caps.setRedBits(5); caps.setGreenBits(5); caps.setBlueBits(5); caps.setAlphaBits(0); + caps.setDoubleBuffered(false); + caps.setOnscreen(false); + caps.setPBuffer(true); + final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) createGLDrawable( createOffscreenSurfaceImpl(sharedDevice, caps, caps, null, 64, 64) ); + if(null!=drawable) { + final GLContext context = drawable.createContext(null); + if (null != context) { + context.setSynchronized(true); + try { + context.makeCurrent(); // could cause exception + madeCurrent = context.isCurrent(); + if(madeCurrent) { + GL gl = context.getGL(); + hasNPOTTextures = gl.isNPOTTextureAvailable(); + hasRECTTextures = gl.isExtensionAvailable("GL_EXT_texture_rectangle"); + hasAppletFloatPixels = gl.isExtensionAvailable("GL_APPLE_float_pixels"); + } + } catch (GLException gle) { + if (DEBUG) { + System.err.println("MacOSXCGLDrawableFactory.createShared: INFO: makeCurrent failed"); + gle.printStackTrace(); + } + } finally { + context.destroy(); + } + } + drawable.destroy(); + } + } + sr = new SharedResource(sharedDevice, madeCurrent, hasNPOTTextures, hasRECTTextures, hasAppletFloatPixels); synchronized(sharedMap) { sharedMap.put(connection, sr); } + removeDeviceTried(connection); if (DEBUG) { System.err.println("MacOSXCGLDrawableFactory.createShared: device: " + sharedDevice); System.err.println("MacOSXCGLDrawableFactory.createShared: context: " + madeCurrent); @@ -232,22 +270,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { if(!caps.isPBuffer()) { return new MacOSXOffscreenCGLDrawable(this, target); } - - // PBuffer GLDrawable Creation - /** - * FIXME: Think about this .. - * should not be necessary ? .. - final List returnList = new ArrayList(); - final GLDrawableFactory factory = this; - Runnable r = new Runnable() { - public void run() { - returnList.add(new MacOSXPbufferCGLDrawable(factory, target)); - } - }; - maybeDoSingleThreadedWorkaround(r); - return (GLDrawableImpl) returnList.get(0); - */ - return new MacOSXPbufferCGLDrawable(this, target); + return new MacOSXPbufferCGLDrawable(this, target, true); } public boolean canCreateGLPbuffer(AbstractGraphicsDevice device) { @@ -257,7 +280,7 @@ public class MacOSXCGLDrawableFactory extends GLDrawableFactoryImpl { protected NativeSurface createOffscreenSurfaceImpl(AbstractGraphicsDevice device,GLCapabilitiesImmutable capsChosen, GLCapabilitiesImmutable capsRequested, GLCapabilitiesChooser chooser, int width, int height) { AbstractGraphicsScreen screen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_MACOSX); WrappedSurface ns = new WrappedSurface(MacOSXCGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen, true)); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java index a429720db..f552ab3dd 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLGraphicsConfiguration.java @@ -41,15 +41,16 @@ import java.util.List; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.nativewindow.AbstractGraphicsScreen; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.opengl.GLCapabilities; import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.MutableGraphicsConfiguration; + import com.jogamp.common.nio.PointerBuffer; -public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class MacOSXCGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { long pixelformat; MacOSXCGLGraphicsConfiguration(AbstractGraphicsScreen screen, @@ -67,10 +68,6 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration this.pixelformat=pixelformat; } - void setChosenCapabilities(GLCapabilitiesImmutable caps) { - super.setChosenCapabilities(caps); - } - protected static List<GLCapabilitiesImmutable> getAvailableCapabilities(MacOSXCGLDrawableFactory factory, AbstractGraphicsDevice device) { MacOSXCGLDrawableFactory.SharedResource sharedResource = factory.getOrCreateOSXSharedResource(device); if(null == sharedResource) { @@ -83,6 +80,8 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration static final int[] cglInternalAttributeToken = new int[] { CGL.kCGLPFAOpenGLProfile, CGL.kCGLPFAColorFloat, + CGL.NSOpenGLPFANoRecovery, + CGL.NSOpenGLPFAAccelerated, CGL.NSOpenGLPFAPixelBuffer, CGL.NSOpenGLPFADoubleBuffer, CGL.NSOpenGLPFAStereo, @@ -114,6 +113,13 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration ivalues[idx] = caps.getPbufferFloatingPointBuffers() ? 1 : 0; break; + case CGL.NSOpenGLPFANoRecovery: + ivalues[idx] = caps.getHardwareAccelerated() ? 1 : 0; + break; + case CGL.NSOpenGLPFAAccelerated: + ivalues[idx] = caps.getHardwareAccelerated() ? 1 : 0; + break; + case CGL.NSOpenGLPFAPixelBuffer: ivalues[idx] = caps.isPBuffer() ? 1 : 0; break; @@ -222,7 +228,7 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration // Use attribute array to select pixel format PointerBuffer fmt = PointerBuffer.allocateDirect(1); - long[] numScreens = new long[1]; + int[] numScreens = new int[1]; int res = CGL.CGLChoosePixelFormat(attrs, 0, fmt, numScreens, 0); if (res != CGL.kCGLNoError) { throw new GLException("Error code " + res + " while choosing pixel format"); @@ -285,6 +291,10 @@ public class MacOSXCGLGraphicsConfiguration extends DefaultGraphicsConfiguration caps.setPbufferFloatingPointBuffers(ivalues[i] != 0); break; + case CGL.NSOpenGLPFAAccelerated: + caps.setHardwareAccelerated(ivalues[i] != 0); + break; + case CGL.NSOpenGLPFAPixelBuffer: caps.setPBuffer(ivalues[i] != 0); break; diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java index 08a531200..ba384fc71 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXExternalCGLContext.java @@ -48,7 +48,6 @@ 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; import jogamp.nativewindow.WrappedSurface; import jogamp.opengl.GLContextShareSet; @@ -61,7 +60,7 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { private MacOSXExternalCGLContext(Drawable drawable, boolean isNSContext, long handle) { super(drawable, null); setOpenGLMode(isNSContext ? GLBackendType.NSOPENGL : GLBackendType.CGL ); - drawable.setExternalCGLContext(this); + drawable.registerContext(this); this.contextHandle = handle; GLContextShareSet.contextCreated(this); setGLFunctionAvailability(false, true, 0, 0, CTX_PROFILE_COMPAT|CTX_OPTION_ANY); @@ -150,16 +149,10 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { // Need to provide the display connection to extension querying APIs static class Drawable extends MacOSXCGLDrawable { - MacOSXExternalCGLContext extCtx; - Drawable(GLDrawableFactory factory, NativeSurface comp) { super(factory, comp, true); } - void setExternalCGLContext(MacOSXExternalCGLContext externalContext) { - extCtx = externalContext; - } - public GLContext createContext(GLContext shareWith) { throw new GLException("Should not call this"); } @@ -175,11 +168,5 @@ public class MacOSXExternalCGLContext extends MacOSXCGLContext { public void setSize(int width, int height) { throw new GLException("Should not call this"); } - - protected void swapBuffersImpl() { - if (extCtx != null) { - extCtx.swapBuffers(); - } - } } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java index bec4cf32a..ae3fa1428 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOffscreenCGLDrawable.java @@ -40,15 +40,15 @@ package jogamp.opengl.macosx.cgl; -import javax.media.opengl.*; -import javax.media.nativewindow.*; -import jogamp.opengl.*; +import javax.media.nativewindow.NativeSurface; +import javax.media.opengl.GLContext; +import javax.media.opengl.GLDrawableFactory; public class MacOSXOffscreenCGLDrawable extends MacOSXPbufferCGLDrawable { public MacOSXOffscreenCGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target); + super(factory, target, true); } public GLContext createContext(GLContext shareWith) { diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java index 97d198c92..4fe6fa484 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLContext.java @@ -57,7 +57,13 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { @Override protected void drawableUpdatedNotify() throws GLException { - if(0==updateHandle || CGL.updateContextNeedsUpdate(updateHandle)) { + final int w = drawable.getWidth(); + final int h = drawable.getHeight(); + final boolean updateContext = ( 0!=updateHandle && CGL.updateContextNeedsUpdate(updateHandle) ) || + w != lastWidth || h != lastHeight; + if(updateContext) { + lastWidth = w; + lastHeight = h; if (contextHandle == 0) { throw new GLException("Context not created"); } @@ -65,11 +71,11 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { } } - protected long updateHandle = 0; - @Override protected boolean createImpl() { boolean res = super.createImpl(); + lastWidth = -1; + lastHeight = -1; if(res && isNSContext()) { if(0 != updateHandle) { throw new InternalError("XXX1"); @@ -89,5 +95,8 @@ public class MacOSXOnscreenCGLContext extends MacOSXCGLContext { updateHandle = 0; } super.destroyImpl(); - } + } + + private long updateHandle = 0; + private int lastWidth, lastHeight; } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java index 24276c39e..80c54042f 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXOnscreenCGLDrawable.java @@ -40,44 +40,20 @@ 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; public class MacOSXOnscreenCGLDrawable extends MacOSXCGLDrawable { - private List<WeakReference<MacOSXCGLContext>> createdContexts = new ArrayList<WeakReference<MacOSXCGLContext>>(); - + protected MacOSXOnscreenCGLDrawable(GLDrawableFactory factory, NativeSurface component) { super(factory, component, false); } public GLContext createContext(GLContext shareWith) { - MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); - // 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)); - } + final MacOSXOnscreenCGLContext ctx= new MacOSXOnscreenCGLContext(this, shareWith); + registerContext(ctx); return ctx; } - protected void swapBuffersImpl() { - 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(); - } - } - } - } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java index c5743b923..f4b71d37d 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLContext.java @@ -33,19 +33,14 @@ package jogamp.opengl.macosx.cgl; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.opengl.GL; -import javax.media.opengl.GL2; -import javax.media.opengl.GLCapabilitiesImmutable; import javax.media.opengl.GLContext; import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; - public class MacOSXPbufferCGLContext extends MacOSXCGLContext { // State for render-to-texture and render-to-texture-rectangle support - private int textureTarget; // e.g. GL_TEXTURE_2D, GL_TEXTURE_RECTANGLE_NV private int texture; // actual texture object public MacOSXPbufferCGLContext(MacOSXPbufferCGLDrawable drawable, @@ -55,7 +50,7 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { public void bindPbufferToTexture() { GL gl = getGL(); - gl.glBindTexture(textureTarget, texture); + gl.glBindTexture(((MacOSXPbufferCGLDrawable)drawable).getTextureTarget(), texture); // FIXME: not clear whether this is really necessary, but since // the API docs seem to imply it is and since it doesn't seem to // impact performance, leaving it in @@ -70,18 +65,10 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { if (newCreated) { // Initialize render-to-texture support if requested - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) drawable.getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GL gl = getGL(); - boolean rect = gl.isGL2GL3() && capabilities.getPbufferRenderToTextureRectangle(); - if (rect) { - if (!gl.isExtensionAvailable("GL_EXT_texture_rectangle")) { - System.err.println("MacOSXPbufferCGLContext: WARNING: GL_EXT_texture_rectangle extension not " + - "supported; skipping requested render_to_texture_rectangle support for pbuffer"); - rect = false; - } - } - textureTarget = (rect ? GL2.GL_TEXTURE_RECTANGLE : GL.GL_TEXTURE_2D); + final GL gl = getGL(); + final MacOSXPbufferCGLDrawable osxPDrawable = (MacOSXPbufferCGLDrawable)drawable; + final int textureTarget = osxPDrawable.getTextureTarget(); + int[] tmp = new int[1]; gl.glGenTextures(1, tmp, 0); texture = tmp[0]; @@ -90,7 +77,9 @@ public class MacOSXPbufferCGLContext extends MacOSXCGLContext { gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_MAG_FILTER, GL.GL_NEAREST); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_S, GL.GL_CLAMP_TO_EDGE); gl.glTexParameteri(textureTarget, GL.GL_TEXTURE_WRAP_T, GL.GL_CLAMP_TO_EDGE); - gl.glCopyTexImage2D(textureTarget, 0, GL.GL_RGB, 0, 0, drawable.getWidth(), drawable.getHeight(), 0); + gl.glTexImage2D(textureTarget, 0, GL.GL_RGB, osxPDrawable.getTextureWidth(), osxPDrawable.getTextureHeight(), + 0, GL.GL_RGB, GL.GL_UNSIGNED_BYTE, null); + gl.glCopyTexSubImage2D(textureTarget, 0, 0, 0, 0, 0, drawable.getWidth(), drawable.getHeight()); } } diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java index fdbfaf6d6..4c985fd00 100644 --- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXPbufferCGLDrawable.java @@ -51,14 +51,10 @@ import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; import javax.media.opengl.GLProfile; -import jogamp.opengl.Debug; - import com.jogamp.common.nio.PointerBuffer; +import com.jogamp.opengl.util.GLBuffers; - -public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { - private static final boolean DEBUG = Debug.debug("MacOSXPbufferCGLDrawable"); - +public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // Abstract interface for implementation of this drawable (either // NSOpenGL-based or CGL-based) interface GLBackendImpl { @@ -76,34 +72,50 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { // 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) { - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(); + public MacOSXPbufferCGLDrawable(GLDrawableFactory factory, NativeSurface target, boolean realizeNow) { + super(factory, target, false); - if (DEBUG) { - System.err.println("Created pbuffer " + this); + if(realizeNow) { + setRealized(true); } } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } public GLContext createContext(GLContext shareWith) { - return new MacOSXPbufferCGLContext(this, shareWith); + final MacOSXPbufferCGLContext ctx = new MacOSXPbufferCGLContext(this, shareWith); + registerContext(ctx); + return ctx; } - protected void destroyImpl() { + @Override + protected long getNSViewHandle() { + // pbuffer handle is NSOpenGLPixelBuffer + 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(); impl.destroy(pBuffer); @@ -112,73 +124,56 @@ public class MacOSXPbufferCGLDrawable extends MacOSXCGLDrawable { } } - public long getHandle() { - return pBuffer; - } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); + private void createPbuffer() { + final NativeSurface ns = getNativeSurface(); + final DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); + final GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); + final GLProfile glProfile = capabilities.getGLProfile(); + MacOSXCGLDrawableFactory.SharedResource sr = ((MacOSXCGLDrawableFactory)factory).getOrCreateOSXSharedResource(config.getScreen().getDevice()); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); } - } - private void createPbuffer() { - NativeSurface ns = getNativeSurface(); - DefaultGraphicsConfiguration config = (DefaultGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); - GLCapabilitiesImmutable capabilities = (GLCapabilitiesImmutable)config.getChosenCapabilities(); - GLProfile glProfile = capabilities.getGLProfile(); - int renderTarget; - if (glProfile.isGL2GL3() && capabilities.getPbufferRenderToTextureRectangle()) { - renderTarget = GL2.GL_TEXTURE_RECTANGLE; + if ( capabilities.getPbufferRenderToTextureRectangle() && null!=sr && sr.isRECTTextureAvailable() ) { + pBufferTexTarget = GL2.GL_TEXTURE_RECTANGLE; + } else { + pBufferTexTarget = GL.GL_TEXTURE_2D; + } + if ( GL2.GL_TEXTURE_RECTANGLE == pBufferTexTarget || ( null!=sr && sr.isNPOTTextureAvailable() ) ) { + pBufferTexWidth = getWidth(); + pBufferTexHeight = getHeight(); } else { - int w = getNextPowerOf2(getWidth()); - int h = getNextPowerOf2(getHeight()); - ((SurfaceChangeable)ns).setSize(w, h); - renderTarget = GL.GL_TEXTURE_2D; + pBufferTexWidth = GLBuffers.getNextPowerOf2(getWidth()); + pBufferTexHeight = GLBuffers.getNextPowerOf2(getHeight()); } int internalFormat = GL.GL_RGBA; if (capabilities.getPbufferFloatingPointBuffers()) { - // FIXME: want to check availability of GL_APPLE_float_pixels - // extension, but need valid OpenGL context in order to do so -- - // in worst case would need to create dummy window / GLCanvas - // (undesirable) -- could maybe also do this with pbuffers - /* - if (!gl.isExtensionAvailable("GL_APPLE_float_pixels")) { - throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); - } - */ - if(glProfile.isGL2GL3()) { - switch (capabilities.getRedBits()) { + if(!glProfile.isGL2GL3() || null==sr || sr.isAppletFloatPixelsAvailable()) { + throw new GLException("Floating-point support (GL_APPLE_float_pixels) not available"); + } + switch (capabilities.getRedBits()) { case 16: internalFormat = GL2.GL_RGBA_FLOAT16_APPLE; break; case 32: internalFormat = GL2.GL_RGBA_FLOAT32_APPLE; break; default: throw new GLException("Invalid floating-point bit depth (only 16 and 32 supported)"); - } - } else { - internalFormat = GL.GL_RGBA; } } - - pBuffer = impl.create(renderTarget, internalFormat, getWidth(), getHeight()); + + pBuffer = impl.create(pBufferTexTarget, internalFormat, getWidth(), getHeight()); + if(DEBUG) { + System.err.println("MacOSXPbufferCGLDrawable tex: target "+toHexString(pBufferTexTarget)+ + ", pbufferSize "+getWidth()+"x"+getHeight()+ + ", texSize "+pBufferTexWidth+"x"+pBufferTexHeight+ + ", internal-fmt "+toHexString(internalFormat)); + System.err.println("MacOSXPbufferCGLDrawable pBuffer: "+toHexString(pBuffer)); + // Thread.dumpStack(); + } if (pBuffer == 0) { throw new GLException("pbuffer creation error: CGL.createPBuffer() failed"); } ((SurfaceChangeable)ns).setSurfaceHandle(pBuffer); - - } - - private int getNextPowerOf2(int number) { - if (((number-1) & number) == 0) { - //ex: 8 -> 0b1000; 8-1=7 -> 0b0111; 0b1000&0b0111 == 0 - return number; - } - int power = 0; - while (number > 0) { - number = number>>1; - power++; - } - return (1<<power); } public void setOpenGLMode(GLBackendType mode) { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java index b2c95de39..aa5da9f2b 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsBitmapWGLDrawable.java @@ -57,15 +57,19 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { private long hbitmap; protected WindowsBitmapWGLDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - create(); + super(factory, target, false); + setRealized(true); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - create(); + createBitmap(); } else { - destroyImpl(); + destroyBitmap(); } } @@ -73,7 +77,7 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { return new WindowsBitmapWGLContext(this, shareWith); } - private void create() { + private void createBitmap() { int werr; NativeSurface ns = getNativeSurface(); if(DEBUG) { @@ -153,7 +157,7 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { config.updateGraphicsConfiguration(getFactory(), ns, null); } - protected void destroyImpl() { + protected void destroyBitmap() { NativeSurface ns = getNativeSurface(); if (ns.getSurfaceHandle() != 0) { // Must destroy bitmap and device context @@ -165,11 +169,4 @@ public class WindowsBitmapWGLDrawable extends WindowsWGLDrawable { ((SurfaceChangeable)ns).setSurfaceHandle(0); } } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } - } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java index 3d0cce725..966ad867f 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsDummyWGLDrawable.java @@ -84,7 +84,7 @@ public class WindowsDummyWGLDrawable extends WindowsWGLDrawable { GLCapabilities caps = new GLCapabilities(glp); WindowsWGLGraphicsConfiguration cfg = WindowsWGLGraphicsConfigurationFactory.createDefaultGraphicsConfiguration(caps, absScreen); GDISurface ns = new GDISurface(cfg, windowHandle); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return new WindowsDummyWGLDrawable(factory, ns, handleWindowLifecycle); } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java index 7be2c1ac7..cda839967 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsPbufferWGLDrawable.java @@ -51,6 +51,7 @@ import javax.media.opengl.GLProfile; import jogamp.nativewindow.windows.GDI; import jogamp.opengl.GLDrawableImpl; +import jogamp.opengl.windows.wgl.WindowsWGLDrawableFactory.SharedResource; import javax.media.opengl.GLCapabilitiesImmutable; @@ -60,27 +61,22 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { private long buffer; // pbuffer handle private int floatMode; - - protected WindowsPbufferWGLDrawable(GLDrawableFactory factory, NativeSurface target, - WindowsWGLDrawableFactory.SharedResource sharedResource) { - super(factory, target, true); - - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(sharedResource); - - if (DEBUG) { - System.err.println("Created pbuffer " + this); - } + + protected WindowsPbufferWGLDrawable(GLDrawableFactory factory, NativeSurface target) { + super(factory, target, false); + + setRealized(true); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - throw new GLException("Recreation via setRealized not supported."); + createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } @@ -88,7 +84,7 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { return new WindowsPbufferWGLContext(this, shareWith); } - protected void destroyImpl() { + protected void destroyPbuffer() { NativeSurface ns = getNativeSurface(); if(0!=buffer) { WGLExt wglExt = cachedWGLExt; @@ -120,23 +116,22 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { return floatMode; } - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } - - private void createPbuffer(WindowsWGLDrawableFactory.SharedResource sharedResource) { + private void createPbuffer() { + WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); + SharedResource sharedResource = ((WindowsWGLDrawableFactory)factory).getOrCreateSharedResource(config.getScreen().getDevice()); long parentHdc = sharedResource.getDrawable().getNativeSurface().getSurfaceHandle(); WGLExt wglExt = sharedResource.getContext().getWGLExt(); + if (DEBUG) { + System.out.println("Pbuffer config: " + config); + } + int[] iattributes = new int [2*WindowsWGLGraphicsConfiguration.MAX_ATTRIBS]; float[] fattributes = new float[1]; int[] floatModeTmp = new int[1]; int niattribs = 0; int width, height; - WindowsWGLGraphicsConfiguration config = (WindowsWGLGraphicsConfiguration) getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); GLCapabilitiesImmutable chosenCaps = (GLCapabilitiesImmutable)config.getChosenCapabilities(); GLProfile glProfile = chosenCaps.getGLProfile(); @@ -260,7 +255,7 @@ public class WindowsPbufferWGLDrawable extends WindowsWGLDrawable { width = tmp[0]; wglExt.wglQueryPbufferARB( buffer, WGLExt.WGL_PBUFFER_HEIGHT_ARB, tmp, 0 ); height = tmp[0]; - ((SurfaceChangeable)ns).setSize(width, height); + ((SurfaceChangeable)ns).surfaceSizeChanged(width, height); } private static String wglGetLastError() { diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java index 4ed9a00c3..fe446e8fe 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawable.java @@ -41,6 +41,7 @@ package jogamp.opengl.windows.wgl; import java.security.AccessController; + import javax.media.nativewindow.NativeSurface; import javax.media.opengl.GLDrawableFactory; import javax.media.opengl.GLException; @@ -74,7 +75,8 @@ public abstract class WindowsWGLDrawable extends GLDrawableImpl { } } - protected void swapBuffersImpl() { + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() long startTime = 0; if (PROFILING) { startTime = System.currentTimeMillis(); diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java index cd22127a3..5a1f997a6 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLDrawableFactory.java @@ -436,33 +436,32 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { } // PBuffer GLDrawable Creation + GLDrawableImpl pbufferDrawable; final AbstractGraphicsDevice device = config.getScreen().getDevice(); + /** + * Similar to ATI Bug https://bugzilla.mozilla.org/show_bug.cgi?id=486277, + * we need to have a context current on the same Display to create a PBuffer. + */ final SharedResource sr = (SharedResource) sharedResourceRunner.getOrCreateShared(device); - if(null==sr) { - throw new IllegalArgumentException("No shared resource for "+device); - } - final List returnList = new ArrayList(); - Runnable r = new Runnable() { - public void run() { - GLContext lastContext = GLContext.getCurrent(); - if (lastContext != null) { + if(null!=sr) { + GLContext lastContext = GLContext.getCurrent(); + if (lastContext != null) { lastContext.release(); - } - sr.context.makeCurrent(); - try { - GLDrawableImpl pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target, sr); - returnList.add(pbufferDrawable); - } finally { + } + sr.context.makeCurrent(); + try { + pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); + } finally { sr.context.release(); if (lastContext != null) { lastContext.makeCurrent(); } - } } - }; - maybeDoSingleThreadedWorkaround(r); - return (GLDrawableImpl) returnList.get(0); + } else { + pbufferDrawable = new WindowsPbufferWGLDrawable(WindowsWGLDrawableFactory.this, target); + } + return pbufferDrawable; } /** @@ -489,7 +488,7 @@ public class WindowsWGLDrawableFactory extends GLDrawableFactoryImpl { AbstractGraphicsScreen screen = DefaultGraphicsScreen.createDefault(NativeWindowFactory.TYPE_WINDOWS); WrappedSurface ns = new WrappedSurface(WindowsWGLGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic( capsChosen, capsRequested, chooser, screen) ); - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); return ns; } diff --git a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java index 989906514..d472d0358 100644 --- a/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java +++ b/src/jogl/classes/jogamp/opengl/windows/wgl/WindowsWGLGraphicsConfiguration.java @@ -37,7 +37,6 @@ import java.util.ArrayList; import java.util.List; import javax.media.nativewindow.AbstractGraphicsScreen; -import javax.media.nativewindow.DefaultGraphicsConfiguration; import javax.media.nativewindow.NativeSurface; import javax.media.nativewindow.AbstractGraphicsDevice; import javax.media.opengl.GL; @@ -48,13 +47,14 @@ import javax.media.opengl.GLException; import javax.media.opengl.GLPbuffer; import javax.media.opengl.GLProfile; +import jogamp.nativewindow.MutableGraphicsConfiguration; import jogamp.nativewindow.windows.DWM_BLURBEHIND; import jogamp.nativewindow.windows.GDI; import jogamp.nativewindow.windows.MARGINS; import jogamp.nativewindow.windows.PIXELFORMATDESCRIPTOR; import jogamp.opengl.GLGraphicsConfigurationUtil; -public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguration implements Cloneable { +public class WindowsWGLGraphicsConfiguration extends MutableGraphicsConfiguration implements Cloneable { // Keep this under the same debug flag as the drawable factory for convenience protected static final boolean DEBUG = jogamp.opengl.Debug.debug("GraphicsConfiguration"); @@ -733,10 +733,10 @@ public class WindowsWGLGraphicsConfiguration extends DefaultGraphicsConfiguratio static PIXELFORMATDESCRIPTOR createPixelFormatDescriptor(long hdc, int pfdID) { PIXELFORMATDESCRIPTOR pfd = PIXELFORMATDESCRIPTOR.create(); - pfd.setNSize((short) pfd.size()); + pfd.setNSize((short) PIXELFORMATDESCRIPTOR.size()); pfd.setNVersion((short) 1); if(0 != hdc && 1 <= pfdID) { - if (GDI.DescribePixelFormat(hdc, pfdID, pfd.size(), pfd) == 0) { + if (GDI.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()); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java index 68bdb4ab8..720a1c293 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11DummyGLXDrawable.java @@ -59,7 +59,7 @@ public class X11DummyGLXDrawable extends X11OnscreenGLXDrawable { dummyWindow = X11Util.CreateDummyWindow(dpy, scrn, visualID, f_dim, f_dim); ns.setSurfaceHandle( dummyWindow ); - ns.setSize(f_dim, f_dim); + ns.surfaceSizeChanged(f_dim, f_dim); updateHandle(); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java index eb286cdf0..c3d2530f2 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11ExternalGLXDrawable.java @@ -85,7 +85,7 @@ public class X11ExternalGLXDrawable extends X11GLXDrawable { } WrappedSurface ns = new WrappedSurface(cfg); ns.setSurfaceHandle(drawable); - ns.setSize(w, h); + ns.surfaceSizeChanged(w, h); return new X11ExternalGLXDrawable(factory, ns); } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java index d2ce629df..d27b9a92b 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawable.java @@ -42,6 +42,7 @@ package jogamp.opengl.x11.glx; import javax.media.nativewindow.*; import javax.media.opengl.*; + import jogamp.opengl.*; public abstract class X11GLXDrawable extends GLDrawableImpl { @@ -64,9 +65,10 @@ public abstract class X11GLXDrawable extends GLDrawableImpl { } } - protected void swapBuffersImpl() { - GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); - } + protected final void swapBuffersImpl() { + // single-buffer is already filtered out @ GLDrawableImpl#swapBuffers() + GLX.glXSwapBuffers(getNativeSurface().getDisplayHandle(), getHandle()); + } //--------------------------------------------------------------------------- // Internals only below this point diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java index 51316dc77..d040775ed 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11GLXDrawableFactory.java @@ -423,7 +423,7 @@ public class X11GLXDrawableFactory extends GLDrawableFactoryImpl { WrappedSurface ns = new WrappedSurface( X11GLXGraphicsConfigurationFactory.chooseGraphicsConfigurationStatic(capsChosen, capsRequested, chooser, screen) ); if(ns != null) { - ns.setSize(width, height); + ns.surfaceSizeChanged(width, height); } return ns; } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java index 8ef642322..8cea2a550 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11OnscreenGLXDrawable.java @@ -56,14 +56,16 @@ public class X11OnscreenGLXDrawable extends X11GLXDrawable { } @SuppressWarnings("unused") + @Override public long getHandle() { if(USE_GLXWINDOW && useGLXWindow) { return glXWindow; } - return getNativeSurface().getSurfaceHandle(); + return super.getHandle(); } @SuppressWarnings("unused") + @Override protected void destroyHandle() { if(USE_GLXWINDOW && 0!=glXWindow) { GLX.glXDestroyWindow(getNativeSurface().getDisplayHandle(), glXWindow); @@ -72,7 +74,7 @@ public class X11OnscreenGLXDrawable extends X11GLXDrawable { } } - /** must be locked already */ + @Override protected void updateHandle() { if(USE_GLXWINDOW) { X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration)getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration(); diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java index 8ea989267..7bfffd091 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PbufferGLXDrawable.java @@ -48,24 +48,24 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { /* GLCapabilities caps, GLCapabilitiesChooser chooser, int width, int height */ - super(factory, target, true); + super(factory, target, false); - if (DEBUG) { - System.out.println("Pbuffer config: " + getNativeSurface().getGraphicsConfiguration().getNativeGraphicsConfiguration()); - } - - createPbuffer(); + setRealized(true); if (DEBUG) { System.err.println("Created pbuffer " + this); } } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { createPbuffer(); } else { - destroyImpl(); + destroyPbuffer(); } } @@ -73,7 +73,7 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { return new X11PbufferGLXContext(this, shareWith); } - protected void destroyImpl() { + protected void destroyPbuffer() { NativeSurface ns = getNativeSurface(); if (ns.getSurfaceHandle() != 0) { GLX.glXDestroyPbuffer(ns.getDisplayHandle(), ns.getSurfaceHandle()); @@ -86,7 +86,10 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { AbstractGraphicsScreen aScreen = config.getScreen(); AbstractGraphicsDevice aDevice = aScreen.getDevice(); long display = aDevice.getHandle(); - int screen = aScreen.getIndex(); + + if (DEBUG) { + System.out.println("Pbuffer config: " + config); + } if (display==0) { throw new GLException("Null display"); @@ -129,17 +132,11 @@ public class X11PbufferGLXDrawable extends X11GLXDrawable { int width = tmp[0]; GLX.glXQueryDrawable(display, pbuffer, GLX.GLX_HEIGHT, tmp, 0); int height = tmp[0]; - ((SurfaceChangeable)ns).setSize(width, height); + ((SurfaceChangeable)ns).surfaceSizeChanged(width, height); } public int getFloatingPointMode() { // Floating-point pbuffers currently require NVidia hardware on X11 return GLPbuffer.NV_FLOAT; } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java index f5d321561..6ede6e13d 100644 --- a/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java +++ b/src/jogl/classes/jogamp/opengl/x11/glx/X11PixmapGLXDrawable.java @@ -48,15 +48,19 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { private long pixmap; protected X11PixmapGLXDrawable(GLDrawableFactory factory, NativeSurface target) { - super(factory, target, true); - create(); + super(factory, target, false); + setRealized(true); } + protected void destroyImpl() { + setRealized(false); + } + protected void setRealizedImpl() { if(realized) { - create(); + createPixmap(); } else { - destroyImpl(); + destroyPixmap(); } } @@ -64,7 +68,7 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { return new X11PixmapGLXContext(this, shareWith); } - private void create() { + private void createPixmap() { NativeSurface ns = getNativeSurface(); X11GLXGraphicsConfiguration config = (X11GLXGraphicsConfiguration) ns.getGraphicsConfiguration().getNativeGraphicsConfiguration(); XVisualInfo vis = config.getXVisualInfo(); @@ -93,7 +97,7 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { } } - protected void destroyImpl() { + protected void destroyPixmap() { if (pixmap == 0) return; NativeSurface ns = getNativeSurface(); @@ -128,10 +132,4 @@ public class X11PixmapGLXDrawable extends X11GLXDrawable { ((SurfaceChangeable)ns).setSurfaceHandle(0); display = 0; } - - protected void swapBuffersImpl() { - if(DEBUG) { - System.err.println("unhandled swapBuffersImpl() called for: "+this); - } - } } diff --git a/src/jogl/native/macosx/ContextUpdater.h b/src/jogl/native/macosx/ContextUpdater.h index 3cf7315af..f00b2be57 100644 --- a/src/jogl/native/macosx/ContextUpdater.h +++ b/src/jogl/native/macosx/ContextUpdater.h @@ -25,17 +25,13 @@ This notification is sent whenever an NSView that has an attached NSSurface chan @interface ContextUpdater : NSObject { @protected + pthread_mutex_t resourceLock; NSView * view; NSRect viewRect; NSOpenGLContext *ctx; BOOL viewUpdated; } -- (void) lock; -- (void) lockInFunction:(char *)func atLine:(int)line; -- (void) unlock; -- (void) unlockInFunction:(char *)func atLine:(int)line; - - (id) initWithContext:(NSOpenGLContext *)context view: (NSView *)nsView; - (void) update:(NSNotification *)notification; diff --git a/src/jogl/native/macosx/ContextUpdater.m b/src/jogl/native/macosx/ContextUpdater.m index 21f98ad5e..a3b9b5c8c 100644 --- a/src/jogl/native/macosx/ContextUpdater.m +++ b/src/jogl/native/macosx/ContextUpdater.m @@ -1,43 +1,26 @@ #import "ContextUpdater.h" #import <pthread.h> -@implementation ContextUpdater -{ -} - -static pthread_mutex_t resourceLock = PTHREAD_MUTEX_INITIALIZER; - -static void printLockDebugInfo(char *message, char *func, int line) -{ - fprintf(stderr, "%s in function: \"%s\" at line: %d\n", message, func, line); - fflush(NULL); -} - -- (void) lock -{ - pthread_mutex_lock(&resourceLock); -} +#define VERBOSE_ON 1 -- (void) lockInFunction:(char *)func atLine:(int)line -{ - printLockDebugInfo("locked ", func, line); - [self lock]; -} +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif -- (void) unlock -{ - pthread_mutex_unlock(&resourceLock); -} +#ifndef CGL_VERSION_1_3 + #warning this SDK doesn't support OpenGL profile +#endif -- (void) unlockInFunction:(char *)func atLine:(int)line +@implementation ContextUpdater { - printLockDebugInfo("unlocked", func, line); - [self unlock]; } - (void) update:(NSNotification *)notification { - [self lock]; + pthread_mutex_lock(&resourceLock); NSRect r = [view frame]; if(viewRect.origin.x != r.origin.x || @@ -47,41 +30,47 @@ static void printLockDebugInfo(char *message, char *func, int line) viewUpdated = TRUE; viewRect = r; } - - [self unlock]; + + pthread_mutex_unlock(&resourceLock); } - (BOOL) needsUpdate { BOOL r; - [self lock]; + pthread_mutex_lock(&resourceLock); r = viewUpdated; viewUpdated = FALSE; - [self unlock]; + pthread_mutex_unlock(&resourceLock); return r; } - (id) initWithContext:(NSOpenGLContext *)context view: (NSView *)nsView { + DBG_PRINT("ContextUpdater::init.0 view %p, ctx %p\n", view, ctx); + pthread_mutex_init(&resourceLock, NULL); // fast non-recursive ctx = context; view = nsView; [ctx retain]; [view retain]; viewRect = [view frame]; - viewUpdated = FALSE; + viewUpdated = TRUE; [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(update:) name:NSViewGlobalFrameDidChangeNotification object: view]; + DBG_PRINT("ContextUpdater::init.X\n"); return [super init]; } - (void) dealloc { + DBG_PRINT("ContextUpdater::dealloc.0 view %p, ctx %p\n", view, ctx); [[NSNotificationCenter defaultCenter] removeObserver:self]; [view release]; [ctx release]; + pthread_mutex_destroy(&resourceLock); + DBG_PRINT("ContextUpdater::dealloc.X\n"); [super dealloc]; } diff --git a/src/jogl/native/macosx/MacOSXCustomCGLCode.c b/src/jogl/native/macosx/MacOSXCustomCGLCode.c index c29be889d..f8b7a800f 100644 --- a/src/jogl/native/macosx/MacOSXCustomCGLCode.c +++ b/src/jogl/native/macosx/MacOSXCustomCGLCode.c @@ -5,8 +5,7 @@ #include </usr/include/machine/types.h> #include "macosx-window-system.h" -void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { - CGLPixelFormatObj pix = (CGLPixelFormatObj) pixelFormat; +void CGLQueryPixelFormat(CGLPixelFormatObj fmt, int* iattrs, int niattrs, int* ivalues) { // FIXME: think about how specifying this might affect the API int virtualScreen = 0; @@ -14,7 +13,7 @@ void CGLQueryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalu GLint value; for (i = 0; i < niattrs && iattrs[i]>0; i++) { CGLPixelFormatAttribute attr = (CGLPixelFormatAttribute) iattrs[i]; - if ( kCGLNoError == CGLDescribePixelFormat(pix, virtualScreen, attr, &value) ) { + if ( kCGLNoError == CGLDescribePixelFormat(fmt, virtualScreen, attr, &value) ) { ivalues[i] = value; } else { ivalues[i] = 0; diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m new file mode 100644 index 000000000..7233f40ce --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-nsview.m @@ -0,0 +1,140 @@ + +@interface MyNSOpenGLLayer: NSOpenGLLayer +{ +@protected + NSOpenGLContext* ctxShared; + NSView* view; + NSOpenGLPixelFormat* fmt; +@public + volatile BOOL shallDraw; +} + +- (id) initWithContext: (NSOpenGLContext*) ctx + pixelFormat: (NSOpenGLPixelFormat*) pfmt + view: (NSView*) v + opaque: (Bool) opaque; + +@end + +@implementation MyNSOpenGLLayer + +- (id) initWithContext: (NSOpenGLContext*) _ctx + pixelFormat: (NSOpenGLPixelFormat*) _fmt + view: (NSView*) _view + opaque: (Bool) opaque +{ + self = [super init]; + ctxShared = _ctx; + [ctxShared retain]; + + fmt = _fmt; + [fmt retain]; + + view = _view; + [view retain]; + [self setView: view]; + [view setLayer: self]; + [view setWantsLayer: YES]; + + [self setAsynchronous: NO]; + // [self setAsynchronous: YES]; // FIXME: JAU + [self setNeedsDisplayOnBoundsChange: NO]; + [self setOpaque: opaque ? YES : NO]; + shallDraw = NO; + textureID = 0; + DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, view %p, opaque %d\n", self, ctx, fmt, view, opaque); + return self; +} + +- (void)dealloc +{ + [fmt release]; + [ctxShared release]; + [view release]; + DBG_PRINT("MyNSOpenGLLayer::dealloc %p\n", self); + [super dealloc]; +} + +- (void) setOpenGLContext: (NSOpenGLContext*) _ctx +{ + DBG_PRINT("MyNSOpenGLLayer::setOpenGLContext: %p %p -> %p\n", self, [self openGLContext], _ctx); + [super setOpenGLContext: _ctx]; +} + +- (void) setOpenGLPixelFormat: (NSOpenGLPixelFormat*) _fmt +{ + DBG_PRINT("MyNSOpenGLLayer::setOpenGLPixelFormat %p %p -> %p\n", self, fmt, _fmt); + [super setOpenGLPixelFormat: fmt]; +} + +- (NSOpenGLPixelFormat *) openGLPixelFormat +{ + return fmt; +} + +- (void) setView: (NSView*) v +{ + DBG_PRINT("MyNSOpenGLLayer::setView %p %p -> %p (ignored/propagated)\n", self, view, v); + [super setView: view]; // propagate +} + +- (NSOpenGLPixelFormat *)openGLPixelFormatForDisplayMask:(uint32_t)mask +{ + DBG_PRINT("MyNSOpenGLLayer::openGLPixelFormatForDisplayMask %p %d -> %p\n", self, mask, fmt); + return fmt; +} + +- (NSOpenGLContext *)openGLContextForPixelFormat:(NSOpenGLPixelFormat *)pixelFormat +{ + NSOpenGLContext* ctx = NULL; + if(NULL == ctx) { + int viewNotReady[] = { 0 }; + ctx = createContext(ctxShared, view, true, fmt, [self isOpaque], viewNotReady); + } + DBG_PRINT("MyNSOpenGLLayer::openGLContextForPixelFormat %p, fmt %p/%p, view %p, shared %p -> %p\n", + self, fmt, pixelFormat, view, ctxShared, ctx); + return ctx; +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + DBG_PRINT("MyNSOpenGLLayer::canDrawInOpenGLContext %p: %d\n", self, self->shallDraw); + return self->shallDraw; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + self->shallDraw = NO; + + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p\n", self, context, pixelFormat); + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSView* view, Bool opaque) { + return [[MyNSOpenGLLayer alloc] initWithContext:ctx pixelFormat: fmt view: view opaque: opaque]; +} + +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + l->shallDraw = YES; + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:YES]; + // NSView* view = [l view]; + // [view setNeedsDisplay: YES]; // FIXME: JAU + // [view performSelectorOnMainThread:@selector(setNeedsDisplay:) withObject:YES waitUntilDone:YES]; + // [view performSelectorOnMainThread:@selector(display) withObject:nil waitUntilDone:YES]; + DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* l) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + [l release]; + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m new file mode 100644 index 000000000..47f679fac --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m @@ -0,0 +1,466 @@ +#import "MacOSXWindowSystemInterface.h" +#import <QuartzCore/QuartzCore.h> +#import <pthread.h> +#include "timespec.h" + +// +// CADisplayLink only available on iOS >= 3.1, sad, since it's convenient. +// Use CVDisplayLink otherwise. +// +// #define HAS_CADisplayLink 1 +// + +// lock/sync debug output +// +// #define DBG_SYNC 1 +// +#ifdef DBG_SYNC + // #define SYNC_PRINT(...) NSLog(@ ## __VA_ARGS__) + #define SYNC_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define SYNC_PRINT(...) +#endif + +// fps debug output +// +// #define DBG_PERF 1 + +@interface MyNSOpenGLLayer: NSOpenGLLayer +{ +@protected + NSOpenGLPixelBuffer* pbuffer; + int texWidth; + int texHeight; + GLuint textureID; + GLint swapInterval; +#ifdef HAS_CADisplayLink + CADisplayLink* displayLink; +#else + CVDisplayLinkRef displayLink; +#endif + int tc; + struct timespec t0; +@public + pthread_mutex_t renderLock; + pthread_cond_t renderSignal; + BOOL shallDraw; +} + +- (id) setupWithContext: (NSOpenGLContext*) ctx + pixelFormat: (NSOpenGLPixelFormat*) pfmt + pbuffer: (NSOpenGLPixelBuffer*) p + opaque: (Bool) opaque + texWidth: (int) texWidth + texHeight: (int) texHeight; + +- (void)deallocTex; +- (void)disableAnimation; +- (int)getSwapInterval; +- (void)setSwapInterval:(int)interval; +- (void)tick; + +@end + +#ifndef HAS_CADisplayLink + +static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink, + const CVTimeStamp *inNow, + const CVTimeStamp *inOutputTime, + CVOptionFlags flagsIn, + CVOptionFlags *flagsOut, + void *displayLinkContext) +{ + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*)displayLinkContext; + pthread_mutex_lock(&l->renderLock); + #ifdef DBG_PERF + [l tick]; + #endif + pthread_cond_signal(&l->renderSignal); + SYNC_PRINT("-*-"); + pthread_mutex_unlock(&l->renderLock); + [pool release]; + return kCVReturnSuccess; +} + +#endif + +@implementation MyNSOpenGLLayer + +- (id) setupWithContext: (NSOpenGLContext*) _ctx + pixelFormat: (NSOpenGLPixelFormat*) _fmt + pbuffer: (NSOpenGLPixelBuffer*) p + opaque: (Bool) opaque + texWidth: (int) _texWidth + texHeight: (int) _texHeight; +{ + pthread_mutex_init(&renderLock, NULL); // fast non-recursive + pthread_cond_init(&renderSignal, NULL); // no attribute + + pbuffer = p; + [pbuffer retain]; + + // instantiate a deactivated displayLink +#ifdef HAS_CADisplayLink + displayLink = [[CVDisplayLink displayLinkWithTarget:self selector:@selector(setNeedsDisplay)] retain]; + [displayLink setPaused: YES]; +#else + CVReturn cvres; + { + int allDisplaysMask = 0; + int virtualScreen, accelerated, displayMask; + for (virtualScreen = 0; virtualScreen < [_fmt numberOfVirtualScreens]; virtualScreen++) { + [_fmt getValues:&displayMask forAttribute:NSOpenGLPFAScreenMask forVirtualScreen:virtualScreen]; + [_fmt getValues:&accelerated forAttribute:NSOpenGLPFAAccelerated forVirtualScreen:virtualScreen]; + if (accelerated) { + allDisplaysMask |= displayMask; + } + } + cvres = CVDisplayLinkCreateWithOpenGLDisplayMask(allDisplaysMask, &displayLink); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkCreateWithOpenGLDisplayMask %X failed: %d\n", self, allDisplaysMask, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext(displayLink, [_ctx CGLContextObj], [_fmt CGLPixelFormatObj]); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetCurrentCGDisplayFromOpenGLContext failed: %d\n", self, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + cvres = CVDisplayLinkSetOutputCallback(displayLink, renderMyNSOpenGLLayer, self); + if(kCVReturnSuccess != cvres) { + DBG_PRINT("MyNSOpenGLLayer::init %p, CVDisplayLinkSetOutputCallback failed: %d\n", self, cvres); + displayLink = NULL; + } + } + if(NULL != displayLink) { + CVDisplayLinkStop(displayLink); + } +#endif + [self setAsynchronous: YES]; + + [self setNeedsDisplayOnBoundsChange: YES]; // FIXME: learn how to recreate on size change! + [self setOpaque: opaque ? YES : NO]; + texWidth = _texWidth; + texHeight = _texHeight; + textureID = 0; + swapInterval = -1; + shallDraw = NO; + + CGRect lRect = [self frame]; + + DBG_PRINT("MyNSOpenGLLayer::init %p, ctx %p, pfmt %p, pbuffer %p, opaque %d, pbuffer %dx%d -> tex %dx%d, frame: %lf/%lf %lfx%lf (refcnt %d)\n", + self, _ctx, _fmt, pbuffer, opaque, [pbuffer pixelsWide], [pbuffer pixelsHigh], texWidth, texHeight, + lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height, (int)[self retainCount]); + return self; +} + +- (void)disableAnimation +{ + DBG_PRINT("MyNSOpenGLLayer::disableAnimation: %p (refcnt %d) - displayLink %p\n", self, (int)[self retainCount], displayLink); + pthread_mutex_lock(&renderLock); + [self setAsynchronous: NO]; + if(NULL != displayLink) { +#ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + [displayLink release]; +#else + if(NULL!=displayLink) { + CVDisplayLinkStop(displayLink); + CVDisplayLinkRelease(displayLink); + } +#endif + displayLink = NULL; + } + pthread_mutex_unlock(&renderLock); +} + +- (void)deallocTex +{ + pthread_mutex_lock(&renderLock); + NSOpenGLContext* context = [self openGLContext]; + DBG_PRINT("MyNSOpenGLLayer::deallocTex %p (refcnt %d) - context %p, pbuffer %p\n", self, (int)[self retainCount], context, pbuffer); + if(NULL != pbuffer) { + if(NULL!=context) { + [context makeCurrentContext]; + if(0 != textureID) { + glDeleteTextures(1, &textureID); + textureID = 0; + } + [context clearDrawable]; + } + [pbuffer release]; + pbuffer = NULL; + } + pthread_mutex_unlock(&renderLock); +} + +- (void)dealloc +{ + DBG_PRINT("MyNSOpenGLLayer::dealloc.0 %p (refcnt %d)\n", self, (int)[self retainCount]); + [self disableAnimation]; + [self deallocTex]; + pthread_cond_destroy(&renderSignal); + pthread_mutex_destroy(&renderLock); + [super dealloc]; + DBG_PRINT("MyNSOpenGLLayer::dealloc.X %p\n", self); +} + +- (BOOL)canDrawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + // assume both methods 'canDrawInOpenGLContext' and 'drawInOpenGLContext' + // are called from the same thread subsequently + pthread_mutex_lock(&renderLock); + Bool res = NULL != pbuffer && YES == shallDraw; + if(!res) { + SYNC_PRINT("<0>"); + pthread_mutex_unlock(&renderLock); + } else { + SYNC_PRINT("<"); + } + return res; +} + +- (void)drawInOpenGLContext:(NSOpenGLContext *)context pixelFormat:(NSOpenGLPixelFormat *)pixelFormat + forLayerTime:(CFTimeInterval)timeInterval displayTime:(const CVTimeStamp *)timeStamp +{ + [context makeCurrentContext]; + // FIXME ?? [context update]; + + /** + * v-sync doesn't works w/ NSOpenGLLayer's context .. well :( + * Using CVDisplayLink .. see setSwapInterval() below. + * + if(0 <= swapInterval) { + GLint si; + [context getValues: &si forParameter: NSOpenGLCPSwapInterval]; + if(si != swapInterval) { + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p setSwapInterval: %d -> %d\n", self, si, swapInterval); + [context setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + } + } */ + GLenum textureTarget = [pbuffer textureTarget]; + GLfloat tWidth, tHeight; + { + GLsizei pwidth = [pbuffer pixelsWide]; + GLsizei pheight = [pbuffer pixelsHigh]; + tWidth = textureTarget == GL_TEXTURE_2D ? (GLfloat)pwidth /(GLfloat)texWidth : pwidth; + tHeight = textureTarget == GL_TEXTURE_2D ? (GLfloat)pheight/(GLfloat)texHeight : pheight; + } + Bool texCreated = 0 == textureID; + + if(texCreated) { + glGenTextures(1, &textureID); + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p, ctx %p, pfmt %p tex %dx%d -> %fx%f 0x%X: creating texID 0x%X\n", + self, context, pixelFormat, texWidth, texHeight, tWidth, tHeight, textureTarget, textureID); + + CGRect lRect = [self frame]; + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p frame0: %lf/%lf %lfx%lf\n", + self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + if(lRect.origin.x<0 || lRect.origin.y<0) { + lRect.origin.x = 0; + lRect.origin.y = 0; + [self setFrame: lRect]; + DBG_PRINT("MyNSOpenGLLayer::drawInOpenGLContext %p frame*: %lf/%lf %lfx%lf\n", + self, lRect.origin.x, lRect.origin.y, lRect.size.width, lRect.size.height); + } + } + + glBindTexture(textureTarget, textureID); + + /** + if(texCreated) { + // proper tex size setup + glTexImage2D(textureTarget, 0, GL_RGB, texWidth, texHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + } */ + + [context setTextureImageToPixelBuffer: pbuffer colorBuffer: GL_FRONT]; + + glTexParameteri(textureTarget, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + glTexParameteri(textureTarget, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + + glEnable(textureTarget); + + static GLfloat verts[] = { + -1.0, -1.0, + -1.0, 1.0, + 1.0, 1.0, + 1.0, -1.0 + }; + + GLfloat tex[] = { + 0.0, 0.0, + 0.0, tHeight, + tWidth, tHeight, + tWidth, 0.0 + }; + + glEnableClientState(GL_VERTEX_ARRAY); + glEnableClientState(GL_TEXTURE_COORD_ARRAY); + glVertexPointer(2, GL_FLOAT, 0, verts); + glTexCoordPointer(2, GL_FLOAT, 0, tex); + + glDrawArrays(GL_QUADS, 0, 4); + + glDisableClientState(GL_VERTEX_ARRAY); + glDisableClientState(GL_TEXTURE_COORD_ARRAY); + + glDisable(textureTarget); + glBindTexture(textureTarget, 0); + + [super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp]; + shallDraw = NO; + if(0 >= swapInterval) { + pthread_cond_signal(&renderSignal); + SYNC_PRINT("*"); + } + SYNC_PRINT("1>"); + pthread_mutex_unlock(&renderLock); +} + +- (int)getSwapInterval +{ + return swapInterval; +} + +- (void)setSwapInterval:(int)interval +{ + DBG_PRINT("MyNSOpenGLLayer::setSwapInterval: %d\n", interval); + swapInterval = interval; + if(0 < swapInterval) { + tc = 0; + timespec_now(&t0); + + [self setAsynchronous: NO]; + #ifdef HAS_CADisplayLink + [displayLink setPaused: NO]; + [displayLink setFrameInterval: interval]; + #else + if(NULL!=displayLink) { + CVDisplayLinkStart(displayLink); + // FIXME: doesn't support interval .. + } + #endif + } else { + #ifdef HAS_CADisplayLink + [displayLink setPaused: YES]; + #else + if(NULL!=displayLink) { + CVDisplayLinkStop(displayLink); + } + #endif + [self setAsynchronous: YES]; + } +} + +-(void)tick +{ + tc++; + if(tc%60==0) { + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &t0); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "NSOpenGLLayer: %ld ms / %d frames, %ld ms / frame, %f fps\n", + td_ms, tc, td_ms/tc, (tc * 1000.0) / (float)td_ms ); + fflush(NULL); + } +} + +@end + +NSOpenGLLayer* createNSOpenGLLayer(NSOpenGLContext* ctx, NSOpenGLPixelFormat* fmt, NSOpenGLPixelBuffer* p, Bool opaque, int texWidth, int texHeight) { + // This simply crashes after dealloc() has been called .. ie. ref-count -> 0 too early ? + // However using alloc/init, actual dealloc happens at JAWT destruction, hence too later IMHO. + // return [[MyNSOpenGLLayer layer] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; + + return [[[MyNSOpenGLLayer alloc] init] setupWithContext:ctx pixelFormat: fmt pbuffer: p opaque: opaque texWidth: texWidth texHeight: texHeight]; +} + +void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + pthread_mutex_lock(&l->renderLock); + [l setSwapInterval: interval]; + pthread_mutex_unlock(&l->renderLock); +} + +void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + BOOL ready = NO; + int wr = 0; + pthread_mutex_lock(&l->renderLock); + SYNC_PRINT("{"); + do { + if([l getSwapInterval] <= 0) { + ready = !l->shallDraw; + } + if(NO == ready) { + if(0 < to_ms) { + struct timespec to_abs; + timespec_now(&to_abs); + timespec_addms(&to_abs, to_ms); + wr = pthread_cond_timedwait(&l->renderSignal, &l->renderLock, &to_abs); + #ifdef DBG_SYNC + struct timespec t1, td; + timespec_now(&t1); + timespec_subtract(&td, &t1, &to_abs); + long td_ms = timespec_milliseconds(&td); + fprintf(stderr, "%ld ms", td_ms); + #endif + } else { + pthread_cond_wait (&l->renderSignal, &l->renderLock); + } + ready = !l->shallDraw; + } + } while (NO == ready && 0 == wr) ; + SYNC_PRINT("-%d}", ready); + pthread_mutex_unlock(&l->renderLock); +} + +void setNSOpenGLLayerNeedsDisplay(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + @synchronized(l) { + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + pthread_mutex_lock(&l->renderLock); + SYNC_PRINT("["); + l->shallDraw = YES; + if([l getSwapInterval] > 0) { + // only trigger update if async mode is off (swapInterval>0) + if ( [NSThread isMainThread] == YES ) { + [l setNeedsDisplay]; + } else { + // can't wait, otherwise we may deadlock AWT + [l performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO]; + } + SYNC_PRINT("1]"); + } else { + SYNC_PRINT("0]"); + } + pthread_mutex_unlock(&l->renderLock); + // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l); + [pool release]; + } +} + +void releaseNSOpenGLLayer(NSOpenGLLayer* layer) { + MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer; + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.0: %p (refcnt %d)\n", l, (int)[l retainCount]); + + [l performSelectorOnMainThread:@selector(disableAnimation) withObject:nil waitUntilDone:YES]; + // [l disableAnimation]; + + [l performSelectorOnMainThread:@selector(deallocTex) withObject:nil waitUntilDone:YES]; + // [l deallocTex]; + + [l release]; + DBG_PRINT("MyNSOpenGLLayer::releaseNSOpenGLLayer.X: %p (refcnt %d)\n", l, (int)[l retainCount]); + [pool release]; +} + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.h b/src/jogl/native/macosx/MacOSXWindowSystemInterface.h new file mode 100644 index 000000000..b2d7f9db8 --- /dev/null +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.h @@ -0,0 +1,20 @@ +#import <Cocoa/Cocoa.h> +#import <OpenGL/gl.h> +#import <OpenGL/CGLTypes.h> +#import <jni.h> + +#define VERBOSE_ON 1 + +#ifdef VERBOSE_ON + #define DBG_PRINT(...) NSLog(@ __VA_ARGS__) + // #define DBG_PRINT(...) fprintf(stderr, __VA_ARGS__); fflush(stderr) +#else + #define DBG_PRINT(...) +#endif + +#ifndef CGL_VERSION_1_3 + #warning this SDK doesn't support OpenGL profile +#endif + +#import "macosx-window-system.h" + diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m index 751fba9c0..af269a4b5 100644 --- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m +++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m @@ -14,19 +14,10 @@ #endif */ -#import <Cocoa/Cocoa.h> -#import <OpenGL/gl.h> -#import <OpenGL/CGLTypes.h> -#import <jni.h> - -#ifndef CGL_VERSION_1_3 - #warning this SDK doesn't support OpenGL profile -#endif +#import "MacOSXWindowSystemInterface.h" #import "ContextUpdater.h" -#import "macosx-window-system.h" - // see MacOSXPbufferGLContext.java createPbuffer #define USE_GL_TEXTURE_RECTANGLE_EXT @@ -377,7 +368,7 @@ long validateParameter(NSOpenGLPixelFormatAttribute attribute, long value) return value; } -void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { +NSOpenGLPixelFormat* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; getRendererInfo(); @@ -390,6 +381,18 @@ void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { for (i = 0; i < niattrs && iattrs[i]>0; i++) { int attr = iattrs[i]; switch (attr) { + case NSOpenGLPFANoRecovery: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFANoRecovery; + } + break; + + case NSOpenGLPFAAccelerated: + if (ivalues[i] != 0) { + attribs[idx++] = NSOpenGLPFAAccelerated; + } + break; + case NSOpenGLPFAPixelBuffer: if (ivalues[i] != 0) { attribs[idx++] = NSOpenGLPFAPixelBuffer; @@ -451,9 +454,8 @@ void* createPixelFormat(int* iattrs, int niattrs, int* ivalues) { return fmt; } -void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) { +void queryPixelFormat(NSOpenGLPixelFormat* fmt, int* iattrs, int niattrs, int* ivalues) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; GLint tmp; // FIXME: think about how specifying this might affect the API GLint virtualScreen = 0; @@ -468,16 +470,43 @@ void queryPixelFormat(void* pixelFormat, int* iattrs, int niattrs, int* ivalues) [pool release]; } -void deletePixelFormat(void* pixelFormat) { +void deletePixelFormat(NSOpenGLPixelFormat* fmt) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSOpenGLPixelFormat* fmt = (NSOpenGLPixelFormat*) pixelFormat; [fmt release]; [pool release]; } -void* createContext(void* shareContext, - void* view, - void* pixelFormat, +NSOpenGLContext* getCurrentContext() { + NSOpenGLContext *ctx = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + ctx = [NSOpenGLContext currentContext]; + [pool release]; + return ctx; +} + +CGLContextObj getCGLContext(NSOpenGLContext* ctx) { + void * cglContext = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + cglContext = [ctx CGLContextObj]; + [pool release]; + return cglContext; +} + +NSView* getNSView(NSOpenGLContext* ctx) { + NSView* view = NULL; + + NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; + view = [ctx view]; + [pool release]; + return view; +} + +NSOpenGLContext* createContext(NSOpenGLContext* share, + NSView* view, + Bool isBackingLayerView, + NSOpenGLPixelFormat* fmt, Bool opaque, int* viewNotReady) { @@ -485,27 +514,22 @@ void* createContext(void* shareContext, NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - NSView *nsView = NULL; - NSObject *nsObj = (NSObject*) view; - - if( nsObj != NULL && [nsObj isKindOfClass:[NSView class]] ) { - nsView = (NSView*)nsObj; - } - - if (nsView != NULL) - { + if (view != NULL) { Bool viewReady = true; - if ([nsView lockFocusIfCanDraw] == NO) - { - viewReady = false; + if(!isBackingLayerView) { + if ([view lockFocusIfCanDraw] == NO) { + DBG_PRINT("createContext [view lockFocusIfCanDraw] failed\n"); + viewReady = false; + } } - else - { - NSRect frame = [nsView frame]; - if ((frame.size.width == 0) || (frame.size.height == 0)) - { - [nsView unlockFocus]; + if(viewReady) { + NSRect frame = [view frame]; + if ((frame.size.width == 0) || (frame.size.height == 0)) { + if(!isBackingLayerView) { + [view unlockFocus]; + } + DBG_PRINT("createContext view.frame size %dx%d\n", (int)frame.size.width, (int)frame.size.height); viewReady = false; } } @@ -523,126 +547,80 @@ void* createContext(void* shareContext, } } - NSOpenGLContext* nsContext = [[NSOpenGLContext alloc] - initWithFormat: (NSOpenGLPixelFormat*) pixelFormat - shareContext: (NSOpenGLContext*) shareContext]; + NSOpenGLContext* ctx = [[NSOpenGLContext alloc] initWithFormat:fmt shareContext:share]; - if (nsContext != nil) { - if (nsView != nil) { - if(!opaque) { - GLint zeroOpacity = 0; - [nsContext setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; - } - [nsContext setView:nsView]; - [nsView unlockFocus]; - } + if (ctx != nil) { + if (view != nil) { + if(!opaque) { + GLint zeroOpacity = 0; + [ctx setValues:&zeroOpacity forParameter:NSOpenGLCPSurfaceOpacity]; + } + [ctx setView:view]; + if(!isBackingLayerView) { + [view unlockFocus]; } + } + } [pool release]; - return nsContext; -} - -void * getCurrentContext() { - NSOpenGLContext *nsContext = NULL; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - nsContext = [NSOpenGLContext currentContext]; - [pool release]; - return nsContext;; -} - -void * getCGLContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - void * cglContext = NULL; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - cglContext = [nsContext CGLContextObj]; - [pool release]; - return cglContext; + return ctx; } -void * getNSView(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - void * view = NULL; - +Bool makeCurrentContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - view = [nsContext view]; - [pool release]; - return view; -} - -Bool makeCurrentContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - - NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext makeCurrentContext]; + [ctx makeCurrentContext]; [pool release]; return true; } -Bool clearCurrentContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool clearCurrentContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLContext *currentNSContext = [NSOpenGLContext currentContext]; - if( currentNSContext != nsContext ) { - [nsContext makeCurrentContext]; + if( currentNSContext != ctx ) { + [ctx makeCurrentContext]; } [NSOpenGLContext clearCurrentContext]; [pool release]; return true; } -Bool deleteContext(void* nsJContext, Bool releaseOnMainThread) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool deleteContext(NSOpenGLContext* ctx, Bool releaseOnMainThread) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext clearDrawable]; + [ctx clearDrawable]; if(releaseOnMainThread && NO == [NSThread isMainThread]) { - [nsContext performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES]; + [ctx performSelectorOnMainThread:@selector(release) withObject:nil waitUntilDone:YES]; } else { // would hangs for ~10s for 1 of a shared context set or offscreen context, set releaseOnMainThread=true ! - [nsContext release]; + [ctx release]; } [pool release]; return true; } -Bool flushBuffer(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +Bool flushBuffer(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext flushBuffer]; + [ctx flushBuffer]; [pool release]; return true; } -void setContextOpacity(void* nsJContext, int opacity) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - - [nsContext setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; +void setContextOpacity(NSOpenGLContext* ctx, int opacity) { + [ctx setValues:&opacity forParameter:NSOpenGLCPSurfaceOpacity]; } -void updateContext(void* nsJContext) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - +void updateContext(NSOpenGLContext* ctx) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext update]; + [ctx update]; [pool release]; } -void copyContext(void* destContext, void* srcContext, int mask) { - NSOpenGLContext *src = (NSOpenGLContext*) srcContext; - NSOpenGLContext *dst = (NSOpenGLContext*) destContext; - [dst copyAttributesFromContext: src withMask: mask]; +void copyContext(NSOpenGLContext* dest, NSOpenGLContext* src, int mask) { + [dest copyAttributesFromContext: src withMask: mask]; } -void* updateContextRegister(void* nsJContext, void* nsJView) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSView *nsView = (NSView*)nsJView; - +void* updateContextRegister(NSOpenGLContext* ctx, NSView* view) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: nsContext view: nsView]; + ContextUpdater *contextUpdater = [[ContextUpdater alloc] initWithContext: ctx view: view]; [pool release]; return contextUpdater; } @@ -666,7 +644,7 @@ void updateContextUnregister(void* updater) { [pool release]; } -void* createPBuffer(int renderTarget, int internalFormat, int width, int height) { +NSOpenGLPixelBuffer* createPBuffer(int renderTarget, int internalFormat, int width, int height) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; NSOpenGLPixelBuffer* pBuffer = [[NSOpenGLPixelBuffer alloc] initWithTextureTarget:renderTarget @@ -678,35 +656,25 @@ void* createPBuffer(int renderTarget, int internalFormat, int width, int height) return pBuffer; } -Bool destroyPBuffer(void* buffer) { - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +Bool destroyPBuffer(NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; [pBuffer release]; [pool release]; - return true; } -void setContextPBuffer(void* nsJContext, void* buffer) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +void setContextPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext setPixelBuffer: pBuffer + [ctx setPixelBuffer: pBuffer cubeMapFace: 0 mipMapLevel: 0 - currentVirtualScreen: [nsContext currentVirtualScreen]]; + currentVirtualScreen: [ctx currentVirtualScreen]]; [pool release]; } -void setContextTextureImageToPBuffer(void* nsJContext, void* buffer, int colorBuffer) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; - NSOpenGLPixelBuffer *pBuffer = (NSOpenGLPixelBuffer*)buffer; - +void setContextTextureImageToPBuffer(NSOpenGLContext* ctx, NSOpenGLPixelBuffer* pBuffer, GLenum colorBuffer) { NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init]; - [nsContext setTextureImageToPixelBuffer: pBuffer - colorBuffer: (unsigned long) colorBuffer]; + [ctx setTextureImageToPixelBuffer: pBuffer colorBuffer: colorBuffer]; [pool release]; } @@ -746,10 +714,9 @@ void* getProcAddress(const char *procname) { return NULL; } -void setSwapInterval(void* nsJContext, int interval) { - NSOpenGLContext *nsContext = (NSOpenGLContext*)nsJContext; +void setSwapInterval(NSOpenGLContext* ctx, int interval) { GLint swapInterval = interval; - [nsContext setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; + [ctx setValues: &swapInterval forParameter: NSOpenGLCPSwapInterval]; } Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRamp) { diff --git a/src/jogl/native/timespec.c b/src/jogl/native/timespec.c new file mode 100644 index 000000000..74c1a6901 --- /dev/null +++ b/src/jogl/native/timespec.c @@ -0,0 +1,63 @@ +#include "timespec.h" +#include <sys/time.h> + +void timespec_now(struct timespec *ts) +{ + struct timeval tv; + + // not using clock_gettime() [of rt library] due to portability + gettimeofday(&tv, NULL); + ts->tv_sec = tv.tv_sec; + ts->tv_nsec = tv.tv_usec*1000; +} + +void timespec_addms(struct timespec *ts, long ms) +{ + int sec=ms/1000; + ms=ms-sec*1000; + + // perform the addition + ts->tv_nsec+=ms*1000000; + + // adjust the time + ts->tv_sec+=ts->tv_nsec/1000000000 + sec; + ts->tv_nsec=ts->tv_nsec%1000000000; +} + +void timespec_addns(struct timespec *ts, long ns) +{ + int sec=ns/1000000000; + ns=ns - sec*1000000000; + + // perform the addition + ts->tv_nsec+=ns; + + // adjust the time + ts->tv_sec+=ts->tv_nsec/1000000000 + sec; + ts->tv_nsec=ts->tv_nsec%1000000000; + +} + +int timespec_compare(struct timespec *a, struct timespec *b) +{ + if (a->tv_sec!=b->tv_sec) + return a->tv_sec-b->tv_sec; + return a->tv_nsec-b->tv_nsec; +} + +void timespec_subtract(struct timespec *r, struct timespec *a, struct timespec *b) +{ + r->tv_sec = a->tv_sec; + r->tv_nsec = a->tv_nsec - b->tv_nsec; + if (r->tv_nsec < 0) { + // borrow. + r->tv_nsec += 1000000000; + r->tv_sec --; + } + r->tv_sec = r->tv_sec - b->tv_sec; +} + +long timespec_milliseconds(struct timespec *a) +{ + return a->tv_sec*1000 + a->tv_nsec/1000000; +} diff --git a/src/jogl/native/timespec.h b/src/jogl/native/timespec.h new file mode 100644 index 000000000..671eb4716 --- /dev/null +++ b/src/jogl/native/timespec.h @@ -0,0 +1,19 @@ +#ifndef _timespec_h +#define _timespec_h + +#include <time.h> + +void timespec_now(struct timespec *ts); +void timespec_addms(struct timespec *ts, long ms); +void timespec_addns(struct timespec *ts, long ns); + +/** returns 0: a==b, >0: a>b, <0: a<b */ +int timespec_compare(struct timespec *a, struct timespec *b); + +/** computes r = a - b */ +void timespec_subtract(struct timespec *r, struct timespec *a, struct timespec *b); + +/** convert the timespec into milliseconds (may overflow) */ +long timespec_milliseconds(struct timespec *a); + +#endif /* _timespec_h */ |