Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cocoa drawing on different screens loses performance

I have a document-based app, where each document has one window with an NSScrollView that does some (fairly continuous) drawing using only Cocoa.

To call the drawing, I am using a CVDisplayLink, outlined in the code below:

- (void)windowControllerDidLoadNib:(NSWindowController *) aController {
     //other stuff...
     [self prepareDisplayLink]; //For some reason putting this in awakeFromNib crashes
}

//Prep the display link.
- (void)prepareDisplayLink {
    CVDisplayLinkCreateWithActiveCGDisplays(&displayLink);
    CVDisplayLinkSetCurrentCGDisplay(displayLink, ((CGDirectDisplayID)[[[[[self windowForSheet]screen]deviceDescription]objectForKey:@"NSScreenNumber"]intValue]));
    CVDisplayLinkSetOutputCallback(displayLink, &MyDisplayLinkCallback, self);
}

//Callback to draw frame
static CVReturn MyDisplayLinkCallback(CVDisplayLinkRef displayLink, const CVTimeStamp* now, const CVTimeStamp* outputTime, CVOptionFlags flagsIn, CVOptionFlags* flagsOut, void* displayLinkContext)
{
    NSAutoreleasePool *pool =[[NSAutoreleasePool alloc]init];
    CVReturn result = [(ScrollView*)displayLinkContext getFrameForTime:outputTime];
    [pool drain];
    return result;
}

//Drawing function:
- (CVReturn)getFrameForTime:(const CVTimeStamp*)outputTime
{
    [scrollView lockFocusIfCanDraw];
    [self addToCurrentPostion:(dist/time)*CVDisplayLinkGetActualOutputVideoRefreshPeriod(displayLink)]; //Redraws the scrollview];
    [scrollView unlockFocus];
    return kCVReturnSuccess;

}

//Set the display when the window moves:
- (void)windowDidMove:(NSNotification *)notification {
     if ([notification object] == [self windowForSheet]) {
         CVDisplayLinkSetCurrentCGDisplay(displayLink, ((CGDirectDisplayID)[[[[[self windowForSheet]screen]deviceDescription]objectForKey:@"NSScreenNumber"]intValue]));
     }
}

//Start or stop the animation:
- (IBAction)toggleAnim:(id)sender {
     if (CVDisplayLinkIsRunning(displayLink)) {
        CVDisplayLinkStop(displayLink);
    }
    else {
        CVDisplayLinkStart(displayLink);
    }
}

Rendering Code:

- (void)addToCurrentPostion:(float)amnt {
    fCurrentPosition += amnt; //fCurrentPositon is a float ivar
    if (scrollView) [[scrollView contentView]scrollToPoint:NSMakePoint(0,(int)fCurrentPosition)];
    if (scrollView) [scrollView reflectScrolledClipView:[scrollView contentView]];
}

This works great, and the animation is buttery.....on one screen.

As soon as I move one document off the main screen, onto a second monitor, the animation becomes about as smooth as a car with square wheels. The animation becomes poor in all documents when any one (or more) documents are on the second screen. There can be no documents on the main screen and any on the secondary screen and the animation will degrade also.

I've tried this on multiple types of monitors, and multiple Macs, always ending in these results. To make sure this was not a CVDisplayLink related issue, I also tried rendering using an NSTimer (which the CVDisplayLink is preferable to), with the same results.

What am I doing wrong? Any help is greatly appreciated.

EDIT: I have tried using thread-based drawing too, again with the same results.

EDIT: I've made some progress, in that my thread-based drawing (basically a while loop) works very well on only one screen. (Either the second or first).

like image 406
spudwaffle Avatar asked May 17 '11 00:05

spudwaffle


1 Answers

Have you tried calling prepareDisplayLink everytime the document enters a new screen? Might do the job. You can detect that from windowDidMove function.

like image 183
namar0x0309 Avatar answered Sep 20 '22 10:09

namar0x0309