我有一个相当大CAShapeLayer
的我正在渲染。该层是完全静态的,但它包含在 a 中,UIScrollView
因此它可以四处移动和缩放——基本上,它必须不时地重绘。为了提高这种滚动的帧率,我设置shouldRasterize = YES
了图层,效果很好。因为我从不更改图层的任何属性,所以它永远不会出现光栅化错误,并且我得到了稳定的 60 fps。到处都是击掌,对吧?
直到图层变大一点。最终——不久之后——光栅化的图像变得太大,GPU 无法处理。根据我的控制台,<Notice>: CoreAnimation: surface 2560 x 4288 is too large
它只是不会在屏幕上绘制任何东西。我并不真的责怪它——2560 x 4288
它相当大——但我花了一段时间挠头,才在设备控制台中注意到这一点。
现在,我的问题是:我该如何解决这个限制?如何栅格化一个非常大的图层?
显而易见的解决方案似乎是将层分解为多个子层,例如每个象限一个,并独立地光栅化每个子层。是否有捷径可寻?我可以创建一个从另一层渲染矩形区域的新层吗?还是我应该探索其他一些解决方案?
编辑
创建平铺合成的性能似乎非常糟糕,因为每次进入屏幕时都会重新栅格化图层,从而产生非常生涩的滚动体验。有没有办法缓存这些光栅化?或者这完全是错误的方法?
编辑
好的,这是我当前的解决方案:将图层渲染一次到CGImageRef
. 使用该图像中的子矩形创建多个平铺层,并将它们实际放在屏幕上。
- (CALayer *)getTiledLayerFromLayer:(CALayer *)sourceLayer withHorizontalTiles:(int)horizontalTiles verticalTiles:(int)verticalTiles
{
CALayer *containerLayer = [CALayer layer];
CGFloat tileWidth = sourceLayer.bounds.size.width / horizontalTiles;
CGFloat tileHeight = sourceLayer.bounds.size.height / verticalTiles;
// make sure these are integral, otherwise you'll have image alignment issues!
NSLog(@"tileWidth:%f height:%f", tileWidth, tileHeight);
UIGraphicsBeginImageContextWithOptions(sourceLayer.bounds.size, NO, 0);
CGContextRef tileContext = UIGraphicsGetCurrentContext();
[sourceLayer renderInContext:tileContext];
CGImageRef image = CGBitmapContextCreateImage(tileContext);
UIGraphicsEndImageContext();
for(int horizontalIndex = 0; horizontalIndex < horizontalTiles; horizontalIndex++) {
for(int verticalIndex = 0; verticalIndex < verticalTiles; verticalIndex++) {
CGRect frame = CGRectMake(horizontalIndex * tileWidth, verticalIndex * tileHeight, tileWidth, tileHeight);
CGRect visibleRect = CGRectMake(horizontalIndex / (CGFloat)horizontalTiles, verticalIndex / (CGFloat)verticalTiles, 1.0f / horizontalTiles, 1.0f / verticalTiles);
CALayer *tile = [CALayer layer];
tile.frame = frame;
tile.contents = (__bridge id)image;
tile.contentsRect = visibleRect;
[containerLayer addSublayer:tile];
}
}
CGImageRelease(image);
return containerLayer;
}
这很好用……有点。一方面,我1980 x 3330
在视网膜 iPad 上以 60fps 的速度平移和缩放图层。另一方面,启动需要20秒!因此,虽然这个解决方案解决了我原来的问题,但它给了我一个新问题:如何更快地生成图块?
从字面上看,所有时间都花在了[sourceLayer renderInContext:tileContext];
通话中。这对我来说似乎很奇怪,因为如果我直接添加该层,我可以每秒渲染大约 40 次,根据 Core Animation Instrument。创建我自己的图像上下文是否有可能导致它不使用 GPU 或其他东西?