SCNView frame rate

There’s no API to get any kind of performance information from an SCNView, even as basic as a rolling frame rate.  But it’s not hard to add – you can be notified when each frame is drawn by overriding the -draw method.  For example:

NSDate *nextFrameCounterReset;
NSUInteger frameCount;

- (void)draw {
    NSDate *now = [NSDate date];

    if (nextFrameCounterReset) {
        if (NSOrderedDescending == [now compare:nextFrameCounterReset]) {
            [frameRateView setLabel:frameCount];
            frameCount = 0;
            nextFrameCounterReset = [now dateByAddingTimeInterval:1.0];
        }
    } else {
        nextFrameCounterReset = [now dateByAddingTimeInterval:1.0];
    }

    ++frameCount;

    [super draw];
}

Update:
However, if you’re layer-backed the “draw” method isn’t used. Instead you can override:

- (void)drawInBackingLayerWithCGLContext:(CGLContextObj)arg1;

Like so:

NSDate *nextFrameCounterReset;
NSUInteger frameCount;

- (void)drawInBackingLayerWithCGLContext:(CGLContextObj)arg1 {
    NSDate *now = [NSDate date];

    if (nextFrameCounterReset) {
        if (NSOrderedDescending == [now compare:nextFrameCounterReset]) {
            [frameRateView setLabel:frameCount];
            frameCount = 0;
            nextFrameCounterReset = [now dateByAddingTimeInterval:1.0];
        }
    } else {
        nextFrameCounterReset = [now dateByAddingTimeInterval:1.0];
    }

    ++frameCount;

    [super draw];
}

But don’t. Because in actual fact you can get this information via supported API – the SCNSceneRendererDelegate protocol.  You can register your view as its own delegate, or put your frame rate calculation in another object.  Either way, your code should look something like:

NSDate *nextFrameCounterReset;
NSUInteger frameCount;

- (void)renderer:(id<SCNSceneRenderer>)aRenderer
  didRenderScene:(SCNScene*)scene
          atTime:(NSTimeInterval)time {
    NSDate *now = [NSDate date];

    if (nextFrameCounterReset) {
        if (NSOrderedDescending == [now compare:nextFrameCounterReset]) {
            [frameRateView setLabel:frameCount];
            frameCount = 0;
            nextFrameCounterReset = [now dateByAddingTimeInterval:1.0];
        }
    } else {
        nextFrameCounterReset = [now dateByAddingTimeInterval:1.0];
    }

    ++frameCount;

    [super draw];
}

Leave a Comment