Has anyone played with CADisplayLink in the 3.1 SDK yet? It looks like it is a "timer" that gets fired every time the screen is redrawn (or every x frames). Might be interesting to try plugging into Director in place of NSTimer. Unfortunately would only work with 3.1 devices.
CADisplayLink
(35 posts) (10 voices)-
Posted 2 years ago #
-
It could be a subclass of
Director.
If you have it working, please, send a patch. Thanks.Posted 2 years ago # -
I've been reading several posts about CADisplayLink on the Apple dev forums, it's default setting (1) equates to screen refresh rate and then you can decrease it by setting it to say 2 for 30 fps. Interestingly, the Apple documentation pretty much says and I'm paraphrasing here; do not use anything less than 1 or your device will create a black hole that will suck in the user and the device :). It also says "CADisplayLink should not be subclassed" <- just an FYI
Posted 2 years ago # -
I'll definitely try creating a sub-class of Director that uses it. Probably wont be for a few days since I am a bit backed up here but I'll post my results.
Posted 2 years ago # -
Interesting.... I didn't even look but here's additional info:
https://devforums.apple.com/message/120813#120813snipit: "The template project for opengl in the 3.1 SDK has sample code for detecting if display link is available and falling back on the NSTimer method if it isn't."
Posted 2 years ago # -
Thanks, that helped a lot. I've already got it running with my current Cocos2d game. Definitely seems to help with an occasional stuttering problem I was having.
Posted 2 years ago # -
Here is what I've got so far if anyone wants to play with it. I've only tried it with 0.8.0 since that is the version I am on at the moment.
Director.h
------------- JUST BELOW +(void) useFastDirector; DECLARATION
/** Uses a Director that synchronizes timers with the refresh rate of the display.
*
* Features and Limitations:
* - Only available on 3.1+
* (pre 3.1 devices will gracefully fallback to standard Director)
* - Scheduled timers & drawing are synchronizes with the refresh rate of the display
* - Only supports animation intervals of 1/60 1/30 & 1/15
*/
+(void) useDisplayLinkDirector;
-- AT BOTTOM OF Director.h
/** DisplayLinkDirector is a Director that synchronizes timers with the refresh rate of the display.
*
* Features and Limitations:
* - Only available on 3.1+
* - Scheduled timers & drawing are synchronizes with the refresh rate of the display
* - Only supports animation intervals of 1/60 1/30 & 1/15
*/
@interface DisplayLinkDirector : Director
{
id displayLink;
}@end
Director.m
------------- JUST BELOW +(void) useFastDirector IMPLEMENTATION
+ (void) useDisplayLinkDirector
{
NSAssert(_sharedDirector==nil, @"A Director was alloced. To use Display Link Director this must be the first call to Director");NSString *reqSysVer = @"3.1";
NSString *currSysVer = [[UIDevice currentDevice] systemVersion];if([currSysVer compare:reqSysVer options:NSNumericSearch] != NSOrderedAscending)
{
CCLOG(@"Using Display Link Director. OS Version: %@", currSysVer);
[DisplayLinkDirector sharedDirector];
}
else
{
// Fall back to standard director if pre 3.1
CCLOG(@"Using Standard Director. OS Version: %@", currSysVer);
[Director sharedDirector];
}
}
-- AT BOTTOM of Director.m
// Allows building DisplayLinkDirector for pre-3.1 SDKS
// without getting compiler warnings.
@interface CADisplayLink+ (id) displayLinkWithTarget:(id)arg1 selector:(SEL)arg2;
- (void) addToRunLoop:(id)arg1 forMode:(id)arg2;
- (void) setFrameInterval:(int)interval;
- (void) invalidate;@end
@implementation DisplayLinkDirector
- (void) startAnimation
{
if ( gettimeofday( &lastUpdate, NULL) != 0 ) {
NSException* myException = [NSException
exceptionWithName:@"GetTimeOfDay"
reason:@"GetTimeOfDay abnormal error"
userInfo:nil];
@throw myException;
}// approximate frame rate
// assumes device refreshes at 60 fps
int frameInterval;
if(animationInterval < (1.0 / 45.0))
{
frameInterval = 1;
}
else if(animationInterval < (1.0 / 22.5))
{
frameInterval = 2;
}
else
{
frameInterval = 3;
}displayLink = [NSClassFromString(@"CADisplayLink") displayLinkWithTarget:self selector:@selector(preMainLoop:)];
[displayLink setFrameInterval:frameInterval];
[displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}-(void) preMainLoop:(id)sender
{
[self mainLoop];
}- (void) stopAnimation
{
[displayLink invalidate];
displayLink = nil;
}@end
Posted 2 years ago # -
AWESOME!
What, if any compiler warnings do you get?
Posted 2 years ago # -
No compiler warning if I had posted the correct code.
This line:
@interface CADisplayLink
Should read:
@interface NSObject(CADisplayLink)
That category declaration should fool the compiler into thinking NSObject has the needed selectors (which will be there on 3.1 devices). It's ugly hackery and I'm not sure why I don't get a linker error doing it. It would probably make more sense to use performSelector on the displayLink variable, but I could never figure out how to pass in primitive parameters when doing that.
Posted 2 years ago # -
Awesome!! thanks smallMike. Finally I can get 30fps perfectly vsynced as well as 60fps. Makes a huge difference. It worked really well on iPhone 2nd gen at least. No more NSTimer and vertical beam running out of sync. Which was even more of a problem when trying to run at flawless 30fps...
Add this under the implementation of DisplayLinkDirector to get the setAnimationInterval working:
- (void)setAnimationInterval:(NSTimeInterval)interval
{
animationInterval = interval;
if(displayLink){
[self stopAnimation];
[self startAnimation];
}
}Looking forward of a finalized addition to next cocos version perhaps??
Posted 2 years ago # -
setAnimationInterval should get called on the base class without having to override.
Also, my code for selecting the frame interval is a bit funky. It might be a bit more clear to just have an enum based property on the DisplayLinkDirector to indicate available frame rates. Also, I made a mistake in my comments, setting frameInterval to 3 produces a frame rate of 20 fps. 4 will produce 15 fps (but really who is going to target either of those).
Setting the frameInterval to 1 on my 3GS is amazing. I get a perfectly smooth 60 fps. Too bad I can't rely on that for the other devices.
Posted 2 years ago # -
But your code worked. That's a good stars. Have to clean it up a bit or wait for rick to add it officially to cocos.
I made an option for my game to run it either 60 or 30 fps. I just double tick the logic to get the 30fps mode. This way the game stays the same on all devices and now thanks to this new vsync feature, even the 30fps on iPod 1st gen is smooth as silk... Well as smooth as 30fps can be :D
Posted 2 years ago # -
Noticed a strange thing when using NSAssert with displayLinkDirector. Asserts are showing up in the console, but are not stopping program execution. I can't for the life of me figure out what's going on. When using normal director or fastDirector asserts behave normally.
Anyone have any thoughts on this?
Posted 2 years ago # -
I'm seeing the same thing happen here. My first thought was that maybe the CADisplayLink callback was happening on a separate thread, in which case the Assert might kill that thread but not the main thread. However, from what I can gather in the XCode debugger those calls are happening on the main thread. So I'm at a loss as to why the assert would not be killing the process.
Posted 2 years ago # -
Could you attach the patch here:
http://code.google.com/p/cocos2d-iphone/issues/detail?id=560
?thanks.
Posted 2 years ago # -
Does this only apply to devices with os 3.1? Or is it something that just requires compiling with the latest 3.1 sdk but targeting older OS versions?
Posted 2 years ago # -
@CJ - CADisplayLink is only available on OS 3.1 and up and requires the 3.1 SDK.
Posted 2 years ago # -
@cybergreg Thanks :)
Another Q: Is the restriction to 60, 30, 15 fps a real limitation? or is it just not fully implemented to support other framerates?
I don't see anything in the XCode docs on these 3 magic framerates, so I think the following line can replace that big if/elseif/else block he has to set the frameInterval:
(Note: I did test this on the simulator and it is working, but I don't have a 3.1 os device yet to test with)int frameInterval = floor(animationInterval * 60.0f);Posted 2 years ago # -
BTW, I posted a patch for this CADisplayLink Director:
http://code.google.com/p/cocos2d-iphone/issues/detail?id=560Thanks SmallMike :)
Posted 2 years ago # -
@cj: The CADisplayLink director will only work on 3.1 devices but the code above is written such that it will compile for 2.2. When it is run on any pre 3.1 devices it will use the normal Director code instead of CADisplayLink.
As for the frame rates: with CADisplayLink your timers are tied to the refresh rate on the devices, which is 60 fps. You specify when you want your timer to be called in every X frames. So a frame interval of 1 will result in 60 fps (every screen refresh), 2 will result in 30 fps (every other screen refresh), 3 will result in 20 fps (every third screen refresh), and so on. 60 & 30 fps are the only practical frame rates you can achieve with CADisplayLink (I assume no one wants to target less than 30).
The above code is a bit weird in that it assumes a CADisplayLink frameInterval based on the existing animationInterval property. I'm sure Riq will determine a better way to do that.
Thanks for posting the patch CJ.
Posted 2 years ago # -
Hi guys, interesting thread!
I have a question though: if the CADisplayLink fires exactly 60 times per seconds because it's tied to the hardware refresh rate, what happens if in my game loop the time spent to "render" one frame is bigger than 1/60 seconds?
I guess the CADisplayLink is some kind of interrupt. How does it work?Receptor
Posted 2 years ago # -
@Receptor: not seeing any mention in the documentation, but I believe someone in the Apple Dev forums said it works like an NSTimer in that regard. When CADisplayLink attempts to call your selector, if it is still running from a previous iteration, it will simply not call it and try again the next time around. Haven't tested this, but it seems logical enough.
Posted 2 years ago # -
fixed in r1394. thanks.
Posted 2 years ago # -
refixed on r1396
NEW API:
// Try to use CADisplayLink director // if it fails (SDK < 3.1) use Threaded director if( ! [Director setDirectorType:CCDirectorTypeDisplayLink] ) [Director setDirectorType:CCDirectorTypeThreadMainLoop];since v0.8.2 there are 4 type of directors. They are detailed on Director.h
http://code.google.com/p/cocos2d-iphone/source/browse/trunk/cocos2d/Director.h?spec=svn1396&r=1396#46Posted 2 years ago # -
Any idea what difference to battery life each of these different directors will make? I know the NSTimer Director is easier on the battery than the "Fast" directors, but that's about the extent of my knowledge. Battery is something I'm always concerned about as I have no landline - my iPhone is not only a gaming platform and a development device, but also my primary means of communication.
I'd like to actually perform some comparative tests on battery life, but I don't know how I'd go about something like that. Does anyone have any suggestions? (Sorry if I'm derailing the thread... I've asked about this before but I did not receive any responses.)
Posted 2 years ago # -
The one low framerate I think we do want is 4fps for when director is paused. So the change I made would support the nearest valid framerate.
This is in regard to the following code:
int frameInterval = (int) floor(animationInterval * 60.0f);Posted 2 years ago # -
Hi,
what's the advantage of the threaded Director?
Posted 2 years ago # -
the new
Fast 'threaded' Directoris like theFast 'mono-thread' Director.The main loop will continue to be executed from the main thread, but I think it will have less problems dispatching events.
it's based on this paper:
http://www.slideshare.net/llopis/squeezing-every-drop-of-performance-out-of-the-iphonePosted 2 years ago # -
Excellent, will this new CCDirectorTypeDisplayLink fix the 40fps/60fps switch on 3.1 3GS devices?
Posted 2 years ago #
Reply »
You must log in to post.