我有一个大的NSView
,它显示了一个自定义 Quartz2D 绘图,它以高帧速率反复变化。但是,只有绘图的某些部分可能会因帧而异。到目前为止,我的方法是首先绘制到屏幕外位图上下文,然后从该上下文创建图像,最后使用该图像更新视图的 CoreAnimation 层的内容。
我的第一个问题是,这种方法通常是否有意义,在性能方面是否可行?
绘制到屏幕外位图上下文的速度足够快,并且经过优化以仅重绘脏区域。所以在这一步之后,我有一组矩形,它们标记了屏幕外缓冲区中应该显示在屏幕上的区域。现在,我只需使用从屏幕外位图上下文创建的图像更新 CoreAnimation 层的内容,这基本上可以正常工作,但我会闪烁,看起来新帧很快显示在屏幕上,但不完全(或不在全部)绘制了。我玩过CATransaction lock/unlock/begin/end/flush
, NSView lockFocus/unlockFocus
,NSDisableScreenUpdates/NSEnableScreenUpdates
但还没有找到解决闪烁的方法,所以我想知道真正正确的同步顺序是什么?
这是初始化代码的草图:
NSView* theView = ...
CALayer* layer = [[CALayer new] autorelease];
layer.actions = [NSDictionary dictionaryWithObject:[NSNull null] forKey:@"contents"];
[theView setLayer: layer];
[theView setWantsLayer: YES];
// bitmapContext gets re-created when the view size increases.
CGContextRef bitmapContext = CGBitmapContextCreate(...);
这里是绘图代码的草图:
CGRect[] dirtyRegions = ...
NSDisableScreenUpdates();
[CATransaction begin];
[CATransaction setDisableActions: YES];
// draw into dirty regions of bitmapContext
// ...
// create image from bitmap context
void* buffer = CGBitmapContextGetData(bitmapContext);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, ...);
CGImageRef image = CGImageCreate(..., provider, ...);
// update layer contents, dirty regions are ignored
layer.contents = image;
[CATransaction commit];
NSEnableScreenUpdates();
我还想利用有关脏区的知识。有没有办法使用这种方法只更新屏幕上的脏区域?
谢谢你的帮助!
更新:我想我发现了导致闪烁的问题。我使用来自位图上下文的像素缓冲区创建图像CGImageCreate(...)
。如果我CGBitmapContextCreateImage(...)
改用它,它会起作用。CGBitmapContextCreateImage
写时复制,所以如果我理解正确,它会在位图上下文再次更新时写入像素,这可以解释为什么它不能更早地工作。我读过CGBitmapContextCreateImage
应该小心使用的地方,因为它调用内核可能会影响性能,所以我想我会简单地将相关像素复制到新的图像缓冲区中,同时考虑到脏区。这有意义吗?