可可在不同屏幕上绘图会损失性能

发布于 2024-11-08 11:00:58 字数 2777 浏览 0 评论 0原文

我有一个基于文档的应用程序,其中每个文档都有一个带有 NSScrollView 的窗口,该窗口仅使用 Cocoa 进行一些(相当连续的)绘图。

为了调用绘图,我使用了 CVDisplayLink,在下面的代码中概述:

- (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);
    }
}

渲染代码:

- (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]];
}

这效果很好,并且动画在一个屏幕上是黄油状的......。

一旦我将一个文档从主屏幕移到第二个显示器上,动画就会变得像方形轮子的汽车一样流畅。 当任何一个(或多个)文档位于第二个屏幕上时,所有文档中的动画都会变得很差。 主屏幕上不能有任何文档,辅助屏幕上也不能有任何文档,动画也会降级。

我已经在多种类型的显示器和多台 Mac 上尝试过此操作,但总是以这些结果结束。 为了确保这不是 CVDisplayLink 相关问题,我还尝试使用 NSTimer 进行渲染(CVDisplayLink 更可取),得到了相同的结果。

我做错了什么? 非常感谢任何帮助。

编辑:我也尝试过使用基于线程的绘图,同样得到了相同的结果。

编辑:我已经取得了一些进展,因为我的基于线程的绘图(基本上是一个 while 循环)仅在一个屏幕上运行得很好。 (第二个或第一个)。

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).

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

°如果伤别离去 2024-11-15 11:00:58

您是否尝试过在每次文档进入新屏幕时调用prepareDisplayLink?可能会完成这项工作。您可以从 windowDidMove 函数中检测到这一点。

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

银河中√捞星星 2024-11-15 11:00:58

您重新绘制框架的速度有多快?问题似乎是该卡只能不断地重新绘制一定量的数据。您是否重新绘制彼此独立的每个动画?尝试同时重新绘制所有动画。

问题似乎来自与视频卡的设备驱动程序和您的逻辑的直接交互。祝你好运。

How fast are you re-drawing the frames? The problem seems to be that the card can only keep re-drawing a certain amount of data. Are you re-drawing each animation independent from each other? Try re-drawing all the animations at the same time.

Problem seems to come from amdirect interaction with the device driver of the video card and with your logic. Good luck.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文