aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java25
-rw-r--r--src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m88
-rw-r--r--src/jogl/native/macosx/MacOSXWindowSystemInterface.m36
-rw-r--r--src/jogl/native/timespec.c14
-rw-r--r--src/jogl/native/timespec.h1
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java32
-rw-r--r--src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java13
7 files changed, 150 insertions, 59 deletions
diff --git a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
index 7d7dae950..3cd4b340c 100644
--- a/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
+++ b/src/jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java
@@ -396,11 +396,12 @@ public abstract class MacOSXCGLContext extends GLContextImpl
class NSOpenGLImpl implements GLBackendImpl {
long nsOpenGLLayer = 0;
long nsOpenGLLayerPFmt = 0;
- int vsyncTimeout = 16;
+ float screenVSyncTimeout; // microSec
+ int vsyncTimeout; // microSec - for nsOpenGLLayer mode
public boolean isNSContext() { return true; }
- public long create(long share, int ctp, int major, int minor) {
+ public long create(long share, int ctp, int major, int minor) {
long ctx = 0;
final MacOSXCGLDrawable drawable = (MacOSXCGLDrawable) MacOSXCGLContext.this.drawable;
final NativeSurface surface = drawable.getNativeSurface();
@@ -415,6 +416,8 @@ public abstract class MacOSXCGLContext extends GLContextImpl
return 0;
}
config.setChosenPixelFormat(pixelFormat);
+ int sRefreshRate = CGL.getScreenRefreshRate(drawable.getNativeSurface().getGraphicsConfiguration().getScreen().getIndex());
+ screenVSyncTimeout = 1000000f / (float)sRefreshRate;
if(DEBUG) {
System.err.println("NS create OSX>=lion "+isLionOrLater);
System.err.println("NS create backendType: "+drawable.getOpenGLMode());
@@ -424,6 +427,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl
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()));
+ System.err.println("NS create screen refresh-rate: "+sRefreshRate+" hz, "+screenVSyncTimeout+" micros");
// Thread.dumpStack();
}
try {
@@ -483,6 +487,7 @@ public abstract class MacOSXCGLContext extends GLContextImpl
System.err.println("NS create nsOpenGLLayer "+toHexString(nsOpenGLLayer)+", texSize "+texWidth+"x"+texHeight+", "+drawable);
}
backingLayerHost.attachSurfaceLayer(nsOpenGLLayer);
+ setSwapInterval(1); // enabled per default in layered surface
}
} finally {
if(0!=pixelFormat) {
@@ -554,23 +559,17 @@ public abstract class MacOSXCGLContext extends GLContextImpl
public boolean setSwapInterval(int interval) {
if(0 != nsOpenGLLayer) {
CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, interval);
+ vsyncTimeout = interval * (int)screenVSyncTimeout;
+ if(DEBUG) { System.err.println("NS setSwapInterval: "+vsyncTimeout+" micros"); }
}
CGL.setSwapInterval(contextHandle, interval);
- if (interval == 0) {
- // v-sync is disabled, frames were drawn as quickly as possible without adding any
- // timeout delay.
- vsyncTimeout = 0;
- } else {
- // v-sync is enabled. Swaping interval of 1 means a
- // timeout of 16ms -> 60Hz, 60fps
- vsyncTimeout = interval * 16;
- }
return true;
}
public boolean swapBuffers() {
- if(0 != nsOpenGLLayer && 0 < vsyncTimeout) {
- // sync w/ CALayer renderer - wait until next frame is required (v-sync)
+ if( 0 != nsOpenGLLayer ) {
+ // If v-sync is disabled, frames will be drawn as quickly as possible
+ // w/o delay but in sync w/ CALayer. Otherwise wait until next swap interval (v-sync).
CGL.waitUntilNSOpenGLLayerIsReady(nsOpenGLLayer, vsyncTimeout);
}
if(CGL.flushBuffer(contextHandle)) {
diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m
index 6071f9610..66bd10f89 100644
--- a/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m
+++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface-pbuffer.m
@@ -33,6 +33,8 @@
int texHeight;
GLuint textureID;
GLint swapInterval;
+ GLint swapIntervalCounter;
+ struct timespec lastWaitTime;
#ifdef HAS_CADisplayLink
CADisplayLink* displayLink;
#else
@@ -78,8 +80,14 @@ static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
#ifdef DBG_PERF
[l tick];
#endif
- pthread_cond_signal(&l->renderSignal);
- SYNC_PRINT("-*-");
+ if(0 < l->swapInterval) {
+ l->swapIntervalCounter++;
+ if(l->swapIntervalCounter>=l->swapInterval) {
+ l->swapIntervalCounter = 0;
+ pthread_cond_signal(&l->renderSignal);
+ SYNC_PRINT("S");
+ }
+ }
pthread_mutex_unlock(&l->renderLock);
[pool release];
return kCVReturnSuccess;
@@ -103,7 +111,9 @@ static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
pthread_cond_init(&renderSignal, NULL); // no attribute
textureID = 0;
- swapInterval = -1;
+ swapInterval = 1; // defaults to on (as w/ new GL profiles)
+ swapIntervalCounter = 0;
+ timespec_now(&lastWaitTime);
shallDraw = NO;
texWidth = _texWidth;
texHeight = _texHeight;
@@ -244,10 +254,10 @@ static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
pthread_mutex_lock(&renderLock);
Bool res = NULL != pbuffer && YES == shallDraw;
if(!res) {
- SYNC_PRINT("<0>");
+ SYNC_PRINT("0");
pthread_mutex_unlock(&renderLock);
} else {
- SYNC_PRINT("<");
+ SYNC_PRINT("1");
}
return res;
}
@@ -336,10 +346,10 @@ static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
[super drawInOpenGLContext: context pixelFormat: pixelFormat forLayerTime: timeInterval displayTime: timeStamp];
shallDraw = NO;
if(0 >= swapInterval) {
- pthread_cond_signal(&renderSignal);
- SYNC_PRINT("*");
+ pthread_cond_signal(&renderSignal); // just to wake up
+ SYNC_PRINT("s");
}
- SYNC_PRINT("1>");
+ SYNC_PRINT("$");
pthread_mutex_unlock(&renderLock);
}
@@ -352,6 +362,7 @@ static CVReturn renderMyNSOpenGLLayer(CVDisplayLinkRef displayLink,
{
DBG_PRINT("MyNSOpenGLLayer::setSwapInterval: %d\n", interval);
swapInterval = interval;
+ swapIntervalCounter = 0;
if(0 < swapInterval) {
tc = 0;
timespec_now(&t0);
@@ -409,7 +420,7 @@ void setNSOpenGLLayerSwapInterval(NSOpenGLLayer* layer, int interval) {
pthread_mutex_unlock(&l->renderLock);
}
-void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms) {
+void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_micros) {
MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
BOOL ready = NO;
int wr = 0;
@@ -420,17 +431,23 @@ void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms) {
ready = !l->shallDraw;
}
if(NO == ready) {
- if(0 < to_ms) {
- struct timespec to_abs;
- timespec_now(&to_abs);
- timespec_addms(&to_abs, to_ms);
+ if(0 < to_micros) {
+ #ifdef DBG_SYNC
+ struct timespec t0, t1, td, td2;
+ timespec_now(&t0);
+ #endif
+ struct timespec to_abs = l->lastWaitTime;
+ timespec_addmicros(&to_abs, to_micros);
+ #ifdef DBG_SYNC
+ timespec_subtract(&td, &to_abs, &t0);
+ fprintf(stderr, "(%ld) / ", timespec_milliseconds(&td));
+ #endif
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);
+ timespec_subtract(&td, &t1, &t0);
+ timespec_subtract(&td2, &t1, &l->lastWaitTime);
+ fprintf(stderr, "(%ld) / (%ld) ms", timespec_milliseconds(&td), timespec_milliseconds(&td2));
#endif
} else {
pthread_cond_wait (&l->renderSignal, &l->renderLock);
@@ -439,32 +456,25 @@ void waitUntilNSOpenGLLayerIsReady(NSOpenGLLayer* layer, long to_ms) {
}
} while (NO == ready && 0 == wr) ;
SYNC_PRINT("-%d}", ready);
+ timespec_now(&l->lastWaitTime);
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];
- }
+ MyNSOpenGLLayer* l = (MyNSOpenGLLayer*) layer;
+ NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
+ pthread_mutex_lock(&l->renderLock);
+ l->shallDraw = YES;
+ 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(".");
+ pthread_mutex_unlock(&l->renderLock);
+ // DBG_PRINT("MyNSOpenGLLayer::setNSOpenGLLayerNeedsDisplay %p\n", l);
+ [pool release];
}
void releaseNSOpenGLLayer(NSOpenGLLayer* layer) {
diff --git a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m
index 979e57aee..8ac9f4700 100644
--- a/src/jogl/native/macosx/MacOSXWindowSystemInterface.m
+++ b/src/jogl/native/macosx/MacOSXWindowSystemInterface.m
@@ -745,3 +745,39 @@ Bool setGammaRamp(int tableSize, float* redRamp, float* greenRamp, float* blueRa
void resetGammaRamp() {
CGDisplayRestoreColorSyncSettings();
}
+
+/***
+ * The following static functions are copied out of NEWT's OSX impl. <src/newt/native/MacWindow.m>
+ * May need to push code to NativeWindow, to remove duplication.
+ */
+static NSScreen * NewtScreen_getNSScreenByIndex(int screen_idx) {
+ NSArray *screens = [NSScreen screens];
+ if(screen_idx<0) screen_idx=0;
+ if(screen_idx>=[screens count]) screen_idx=0;
+ return (NSScreen *) [screens objectAtIndex: screen_idx];
+}
+static CGDirectDisplayID NewtScreen_getCGDirectDisplayIDByNSScreen(NSScreen *screen) {
+ // Mind: typedef uint32_t CGDirectDisplayID; - however, we assume it's 64bit on 64bit ?!
+ NSDictionary * dict = [screen deviceDescription];
+ NSNumber * val = (NSNumber *) [dict objectForKey: @"NSScreenNumber"];
+ // [NSNumber integerValue] returns NSInteger which is 32 or 64 bit native size
+ return (CGDirectDisplayID) [val integerValue];
+}
+static long GetDictionaryLong(CFDictionaryRef theDict, const void* key)
+{
+ long value = 0;
+ CFNumberRef numRef;
+ numRef = (CFNumberRef)CFDictionaryGetValue(theDict, key);
+ if (numRef != NULL)
+ CFNumberGetValue(numRef, kCFNumberLongType, &value);
+ return value;
+}
+#define CGDDGetModeRefreshRate(mode) GetDictionaryLong((mode), kCGDisplayRefreshRate)
+
+int getScreenRefreshRate(int scrn_idx) {
+ NSScreen *screen = NewtScreen_getNSScreenByIndex(scrn_idx);
+ CGDirectDisplayID display = NewtScreen_getCGDirectDisplayIDByNSScreen(screen);
+ CFDictionaryRef mode = CGDisplayCurrentMode(display);
+ return CGDDGetModeRefreshRate(mode);
+}
+
diff --git a/src/jogl/native/timespec.c b/src/jogl/native/timespec.c
index 74c1a6901..50f0ca8c5 100644
--- a/src/jogl/native/timespec.c
+++ b/src/jogl/native/timespec.c
@@ -24,6 +24,20 @@ void timespec_addms(struct timespec *ts, long ms)
ts->tv_nsec=ts->tv_nsec%1000000000;
}
+void timespec_addmicros(struct timespec *ts, long micro)
+{
+ int sec=micro/1000000;
+ micro=micro - sec*1000000;
+
+ // perform the addition
+ ts->tv_nsec+=micro*1000;
+
+ // 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;
diff --git a/src/jogl/native/timespec.h b/src/jogl/native/timespec.h
index 671eb4716..f900bfa16 100644
--- a/src/jogl/native/timespec.h
+++ b/src/jogl/native/timespec.h
@@ -5,6 +5,7 @@
void timespec_now(struct timespec *ts);
void timespec_addms(struct timespec *ts, long ms);
+void timespec_addmicros(struct timespec *ts, long micro);
void timespec_addns(struct timespec *ts, long ns);
/** returns 0: a==b, >0: a>b, <0: a<b */
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java
index 5bf341388..c6e224548 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/awt/TestGearsES2AWT.java
@@ -38,9 +38,13 @@ import com.jogamp.newt.event.TraceKeyAdapter;
import com.jogamp.newt.event.TraceWindowAdapter;
import com.jogamp.opengl.test.junit.jogl.demos.es2.GearsES2;
+import com.jogamp.opengl.test.junit.util.MiscUtils;
import com.jogamp.opengl.test.junit.util.UITestCase;
import com.jogamp.opengl.test.junit.util.QuitAdapter;
import java.awt.Frame;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.InputStreamReader;
import java.lang.reflect.InvocationTargetException;
import org.junit.Assert;
@@ -52,6 +56,9 @@ public class TestGearsES2AWT extends UITestCase {
static int width, height;
static boolean firstUIActionOnProcess = false;
static boolean forceES2 = false;
+ static boolean shallUseOffscreenLayer = false;
+ static int swapInterval = 1;
+ static boolean showFPS = false;
@BeforeClass
public static void initClass() {
@@ -69,10 +76,12 @@ public class TestGearsES2AWT extends UITestCase {
final GLCanvas glCanvas = new GLCanvas(caps);
Assert.assertNotNull(glCanvas);
+ glCanvas.setShallUseOffscreenLayer(shallUseOffscreenLayer);
frame.add(glCanvas);
frame.setSize(512, 512);
+ frame.setTitle("Gears AWT Test (translucent "+!caps.isBackgroundOpaque()+"), swapInterval "+swapInterval);
- glCanvas.addGLEventListener(new GearsES2(1));
+ glCanvas.addGLEventListener(new GearsES2(swapInterval));
Animator animator = new Animator(glCanvas);
QuitAdapter quitAdapter = new QuitAdapter();
@@ -115,6 +124,8 @@ public class TestGearsES2AWT extends UITestCase {
static long duration = 500; // ms
public static void main(String args[]) {
+ boolean waitForKey = false;
+
for(int i=0; i<args.length; i++) {
if(args[i].equals("-time")) {
i++;
@@ -123,11 +134,30 @@ public class TestGearsES2AWT extends UITestCase {
} catch (Exception ex) { ex.printStackTrace(); }
} else if(args[i].equals("-es2")) {
forceES2 = true;
+ } else if(args[i].equals("-vsync")) {
+ i++;
+ swapInterval = MiscUtils.atoi(args[i], swapInterval);
+ } else if(args[i].equals("-layered")) {
+ shallUseOffscreenLayer = true;
+ } else if(args[i].equals("-showFPS")) {
+ showFPS = true;
} else if(args[i].equals("-firstUIAction")) {
firstUIActionOnProcess = true;
+ } else if(args[i].equals("-wait")) {
+ waitForKey = true;
}
}
System.err.println("forceES2 "+forceES2);
+ System.err.println("swapInterval "+swapInterval);
+ System.err.println("shallUseOffscreenLayer "+shallUseOffscreenLayer);
+
+ if(waitForKey) {
+ BufferedReader stdin = new BufferedReader(new InputStreamReader(System.in));
+ System.err.println("Press enter to continue");
+ try {
+ System.err.println(stdin.readLine());
+ } catch (IOException e) { }
+ }
org.junit.runner.JUnitCore.main(TestGearsES2AWT.class.getName());
}
}
diff --git a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
index cab46b475..264b62fec 100644
--- a/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
+++ b/src/test/com/jogamp/opengl/test/junit/jogl/demos/es2/newt/TestGearsES2NEWT.java
@@ -77,7 +77,7 @@ public class TestGearsES2NEWT extends UITestCase {
static boolean alwaysOnTop = false;
static boolean fullscreen = false;
static boolean pmvUseBackingArray = true;
- static boolean vsync = false;
+ static int swapInterval = 1;
static boolean waitForKey = false;
static boolean mouseVisible = true;
static boolean mouseConfined = false;
@@ -98,12 +98,12 @@ public class TestGearsES2NEWT extends UITestCase {
}
protected void runTestGL(GLCapabilitiesImmutable caps, boolean undecorated) throws InterruptedException {
- System.err.println("requested: vsync "+vsync+", "+caps);
+ System.err.println("requested: vsync "+swapInterval+", "+caps);
Display dpy = NewtFactory.createDisplay(null);
Screen screen = NewtFactory.createScreen(dpy, screenIdx);
final GLWindow glWindow = GLWindow.create(screen, caps);
Assert.assertNotNull(glWindow);
- glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+"), vsync "+vsync+", size "+wsize+", pos "+wpos);
+ glWindow.setTitle("Gears NEWT Test (translucent "+!caps.isBackgroundOpaque()+"), swapInterval "+swapInterval+", size "+wsize+", pos "+wpos);
glWindow.setSize(wsize.getWidth(), wsize.getHeight());
if(null != wpos) {
glWindow.setPosition(wpos.getX(), wpos.getY());
@@ -114,7 +114,7 @@ public class TestGearsES2NEWT extends UITestCase {
glWindow.setPointerVisible(mouseVisible);
glWindow.confinePointer(mouseConfined);
- final GearsES2 demo = new GearsES2(vsync ? 1 : -1);
+ final GearsES2 demo = new GearsES2(swapInterval);
demo.setPMVUseBackingArray(pmvUseBackingArray);
glWindow.addGLEventListener(demo);
if(waitForKey) {
@@ -276,7 +276,8 @@ public class TestGearsES2NEWT extends UITestCase {
} else if(args[i].equals("-pmvDirect")) {
pmvUseBackingArray = false;
} else if(args[i].equals("-vsync")) {
- vsync = true;
+ i++;
+ swapInterval = MiscUtils.atoi(args[i], swapInterval);
} else if(args[i].equals("-es2")) {
forceES2 = true;
} else if(args[i].equals("-wait")) {
@@ -332,7 +333,7 @@ public class TestGearsES2NEWT extends UITestCase {
System.err.println("atop "+alwaysOnTop);
System.err.println("fullscreen "+fullscreen);
System.err.println("pmvDirect "+(!pmvUseBackingArray));
- System.err.println("vsync "+vsync);
+ System.err.println("swapInterval "+swapInterval);
System.err.println("mouseVisible "+mouseVisible);
System.err.println("mouseConfined "+mouseConfined);
System.err.println("loops "+loops);