Created attachment 328 [details] Full source of the test application demonstrating the bug I have an application built on top of the AWT Applet class. I use NEWT for rendering, and the NewtCanvasAWT class for integrating NEWT with AWT. I use a custom animator to control the frame rendering. But the framerate of my animator is not honored by the application. This happens only on MacOSX. The full source of my test application showing the issue is attached. The target framerate is 120 in the test application, but it hovers around 60. This on a MacBook Pro with a NVidia 320M card and MacOSX Snow Leopard 10.6.8. I'm using the b496 and b666 autobuilds packages for gluegen and jogl, respectively. Also, as a minor detail, the application prints this error: 2012-02-20 09:38:38.304 java[8961:903] invalid drawable just one time right after it starts.
Created attachment 330 [details] Updated NEWT test application
Created attachment 331 [details] Updated AWT test application
Just uploaded updated versions of the test app, using both AWT and NEWT. I added the gl.setSwapInterval(0); call to force disabling vsync, but framerate is still lower in OSX. Other platforms work fine.
I wrote a small patch for the file jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java, which appears to solve the issue reported here. The patch adds the variable vsyncTimeout to the class NSOpenGLImpl. The value of this variable is set to the appropriate timeout in ms needed to call waitUntilNSOpenGLLayerIsReady() in swapBuffers(), according to the desired swap interval. In this way, framerates higher than 60 can be used. Basically, if the user specifies a swap interval of zero, i.e.: v-sync disabled, then vsyncTimeout is set to 2, which corresponds to a theoretical maximum refresh rate of 480Mhz. If the swap interval is equal or larger than 1, then the following formula is used: vsyncTimeout = interval * 16; which yields the correct timeout in milliseconds to use with framerates equal or lower than 60. The downside of this approach is that the timeout interval for framerates higher than 60 is not accurate, since is set to 2ms regardless of the target framerate. I'd like to suggest the addition of a setFramerate method that should do the following: public boolean setFramerate(int fps) { if(fps <= 60) { if(fps <= 15) { return setSwapInterval(3); } else if(fps <= 30) { return setSwapInterval(2); } else { return setSwapInterval(1); } } else { if(0 != nsOpenGLLayer) { CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, 0); } CGL.setSwapInterval(contextHandle, 0); if(fps <= 120) { vsyncTimeout = 8; // 8ms -> 120Mhz } else if(fps <= 240) { vsyncTimeout = 4; // 4ms -> 240Mhz } else { vsyncTimeout = 2; } return true; } } so that it provides finer granularity for framerates above 60.
Created attachment 340 [details] Patch file for MacOSXCGLContext.java
(In reply to comment #4) > I wrote a small patch for the file > jogl/classes/jogamp/opengl/macosx/cgl/MacOSXCGLContext.java, which appears to > solve the issue reported here. > > The patch adds the variable vsyncTimeout to the class NSOpenGLImpl. The value > of this variable is set to the appropriate timeout in ms needed to call > waitUntilNSOpenGLLayerIsReady() in swapBuffers(), according to the desired swap > interval. In this way, framerates higher than 60 can be used. Basically, if the > user specifies a swap interval of zero, i.e.: v-sync disabled, then > vsyncTimeout is set to 2, which corresponds to a theoretical maximum refresh > rate of 480Mhz. If the swap interval is equal or larger than 1, then the > following formula is used: > > vsyncTimeout = interval * 16; > > which yields the correct timeout in milliseconds to use with framerates equal > or lower than 60. > > The downside of this approach is that the timeout interval for framerates > higher than 60 is not accurate, since is set to 2ms regardless of the target > framerate. I'd like to suggest the addition of a setFramerate method that > should do the following: > > public boolean setFramerate(int fps) { > if(fps <= 60) { > if(fps <= 15) { > return setSwapInterval(3); > } else if(fps <= 30) { > return setSwapInterval(2); > } else { > return setSwapInterval(1); > } > } else { > if(0 != nsOpenGLLayer) { > CGL.setNSOpenGLLayerSwapInterval(nsOpenGLLayer, 0); > } > CGL.setSwapInterval(contextHandle, 0); > if(fps <= 120) { > vsyncTimeout = 8; // 8ms -> 120Mhz > } else if(fps <= 240) { > vsyncTimeout = 4; // 4ms -> 240Mhz > } else { > vsyncTimeout = 2; > } > return true; > } > } > > so that it provides finer granularity for framerates above 60. I prefer your second suggestion. Nice job :)
Actually, I think that, when v-sync is disabled, we should remove the waiting altogether, since we want to render frames as fast as possible... so I just disabled the waitUntilNSOpenGLLayerIsReady() call when the vsyncTimeout is zero (no v-sync). This appears to work fine on Mac, Linux and Windows. I'm attaching the new patch after this comment.
Created attachment 345 [details] New patch for MacOSXCGLContext.java that skips waitUntilNSOpenGLLayerIsReady() when v-sync is disabled
Thank you Andres, I hope it works fine now. Works with swap interval 0, 1, 2, ..