为什么我的CAOpenGLLayer更新比以前的NSOpenGLView慢? [英] Why is my CAOpenGLLayer updating slower than my previous NSOpenGLView?

查看:99
本文介绍了为什么我的CAOpenGLLayer更新比以前的NSOpenGLView慢?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个在Mac OS X上渲染OpenGL内容的应用程序.最初它是渲染到NSOpenGLView,然后将其更改为渲染到CAOpenGLLayer子类.

I have an application which renders OpenGL content on Mac OS X. Originally it was rendering to an NSOpenGLView, then I changed it to render to a CAOpenGLLayer subclass.

这样做的时候,我看到了一个巨大的性能损失:帧速率减半,鼠标响应速度降低,口吃(不时停止,最多一秒,在此期间探查器活动报告等待互斥,以将数据加载到GPU ram上) ,并使CPU使用率翻了一番.

When I did so I saw a huge performance loss: halved framerate, lower mouse responsivity, stuttering (stops from time to time, up to a second, during which profiler activity reports waiting on mutex for data to load on GPU ram), and doubled CPU usage.

我正在调查此问题,并有几个问题:

I'm investigating this issue and had a few questions:

  • 其他人是否也看到过类似的表现?
  • 我的CAOpenGLLayer设置是否有问题?
  • 如何实现CAOpenGLLayer和Core Animation框架,即我的OpenGL内容从glDrawElements调用到屏幕的路径是什么,我应该如何做以优化设置的性能?

这是我用于CAOpenGLLayer设置的代码:

Here's my code for CAOpenGLLayer setup:

// my application's entry point (can't be easily changed):
void AppUpdateLogic(); //update application logic. Will load textures
void AppRender(); //executes drawing
void AppEventSink(NSEvent* ev); //handle mouse and keyboard events.
                                //Will do pick renderings

@interface MyCAOpenGLLayer: CAOpenGLLayer
{
    CGLPixelFormatObj   pixelFormat;
    CGLContextObj       glContext;
}
@end

@implementation MyCAOpenGLLayer

- (id)init {
    self = [super init];

    CGLPixelFormatAttribute attributes[] =
    {
        kCGLPFAAccelerated,
        kCGLPFAColorSize, (CGLPixelFormatAttribute)24,
        kCGLPFAAlphaSize, (CGLPixelFormatAttribute)8,
        kCGLPFADepthSize, (CGLPixelFormatAttribute)16,
        (CGLPixelFormatAttribute)0
    };

    GLint numPixelFormats = 0;
    CGLChoosePixelFormat(attributes, &pixelFormat, &numPixelFormats);

    glContext = [super copyCGLContextForPixelFormat:mPixelFormat];

    return self;
}

- (void)drawInCGLContext:(CGLContextObj)inGlContext
             pixelFormat:(CGLPixelFormatObj)inPixelFormat
            forLayerTime:(CFTimeInterval)timeInterval
             displayTime:(const CVTimeStamp *)timeStamp 
{
    AppRender();
    [super drawInCGLContext:inGlContext
                pixelFormat:inPixelFormat
               forLayerTime:timeInterval
                displayTime:timeStamp ]
}

- (void)releaseCGLPixelFormat:(CGLPixelFormatObj)pixelFormat {
    [self release];
}

- (CGLPixelFormatObj)copyCGLPixelFormatForDisplayMask:(uint32_t)mask {
    [self retain];
    return pixelFormat;
}

- (CGLContextObj)copyCGLContextForPixelFormat:(CGLPixelFormatObj)pixelFormat {
    [self retain];
    return glContext;
}

- (void)releaseCGLContext:(CGLContextObj)glContext {
    [self release];
}

@end

@interface MyMainViewController: NSViewController {
    CGLContextObj   glContext;
    CALayer*        myOpenGLLayer;
}

-(void)timerTriggered:(NSTimer*)timer;
@end


@implementation MyMainViewController

-(void)viewDidLoad:(NSView*)view {
    myOpenGLLayer = [[MyCAOpenGLLayer alloc] init];
    [view setLayer:myOpenGLLayer];
    [view setWantsLayer:YES];

    glContext = [myOpenGLLayer copyCGLContextForPixelFormat:nil];

    [NSTimer scheduledTimerWithTimeInterval:1/30.0
                                     target:self
                                   selector:@selector(timerTriggered:)
                                   userInfo:nil
                                    repeats:YES ];
}

- (void)timerTriggered:(NSTimer*)timer {
    CGLContextObj oldContext = CGLContextGetCurrent();
    CGLContextSetCurrent(glContext);
    CGLContextLock(glContext);

    AppUpdateLogic();
    [myOpenGLLayer  setNeedsDisplay:YES];

    CGLContextUnlock(glContext);
    CGLContextSetCurrent(oldContext);
}

- (void)mouseDown:(NSEvent*)event {
    CGLContextObj oldContext = CGLContextGetCurrent();
    CGLContextSetCurrent(glContext);
    CGLContextLock(glContext);

    AppEventSink(event);

    CGLContextUnlock(glContext);
    CGLContextSetCurrent(oldContext);
}
@end

了解我的视频卡不是很强大(具有64 MB共享内存的Intel GMA)可能会很有用.

It may be useful to know my video card isn't very powerful (Intel GMA with 64 MB of shared memory).

推荐答案

在我的一个应用程序中,我从NSOpenGLView切换到CAOpenGLLayer,然后由于后者的更新机制存在一些问题而最终返回.但是,这与您在此处报告的性能问题有所不同.

In one of my applications, I switched from NSOpenGLView to a CAOpenGLLayer, then ended up going back because of a few issues with the update mechanism on the latter. However, that's different from the performance issues you're reporting here.

就您而言,我认为应该负责执行图层内容更新的方式.首先,使用NSTimer触发重绘不能保证更新事件将与显示器的刷新率保持一致.相反,我建议将CAOpenGLLayer的asynchronous属性设置为YES,并使用–canDrawInCGLContext:pixelFormat:forLayerTime:displayTime:来管理更新频率.这将导致OpenGL层与显示同步更新,并且将避免您正在执行的上下文锁定.

In your case, I believe that the way you're performing the update of your layer contents may be to blame. First, using NSTimer to trigger a redraw does not guarantee that the update events will align well with the refresh rate of your display. Instead, I'd suggest setting the CAOpenGLLayer's asynchronous property to YES and using the –canDrawInCGLContext:pixelFormat:forLayerTime:displayTime: to manage the update frequency. This will cause the OpenGL layer to update in sync with the display, and it will avoid the context locking that you're doing.

这样做的缺点(这也是您的NSTimer方法的问题)是在主线程上触发了CAOpenGLLayer委托回调.如果您有阻塞主线程的内容,则显示将冻结.同样,如果您的OpenGL框架更新需要一段时间,则可能会导致UI响应速度降低.

The downside to this (which is also a problem with your NSTimer approach) is that the CAOpenGLLayer delegate callbacks are triggered on the main thread. If you have something that blocks the main thread, your display will freeze. Likewise, if your OpenGL frame updates take a while, they may cause your UI to be less responsive.

这就是导致我使用CVDisplayLink在后台线程上生成OpenGL内容的触发更新的原因.不幸的是,在使用此更新我的CAOpenGLLayer时,我看到了一些渲染工件,因此最终切换回了NSOpenGLView.从那以后,我遇到了一种避免这些伪像的方法,但是NSOpenGLView很好地满足了我们的需求,因此我不再再次切换.

This is what caused me to use a CVDisplayLink to produce a triggered update of my OpenGL content on a background thread. Unfortunately, I saw some rendering artifacts when updating my CAOpenGLLayer with this, so I ended up switching back to an NSOpenGLView. Since then, I've encountered a way to potentially avoid these artifacts, but the NSOpenGLView has been fine for our needs so I haven't switched back once again.

这篇关于为什么我的CAOpenGLLayer更新比以前的NSOpenGLView慢?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆