I’ve created a CALayer subclass in order to draw a checkerboard background pattern. Everything works well and is rendering correctly, however I’ve discovered that performance takes a nosedive when the CALayer is given a large frame.
It seems fairly obvious that I could optimise by shifting the allocation of my CGColorRef and CGPatternRef outside of the drawLayer:inContext: call, but I’m not sure how to go about this as both rely on having a CGContextRef.
As far as my understanding goes, CALayer’s drawing context is actually owned by its parent NSView and is only passed during drawing. If this is the case, how best can I optimise the following code?
void drawCheckerboardPattern(void *info, CGContextRef context)
{
CGColorRef alternateColor = CGColorCreateGenericRGB(1.0, 1.0, 1.0, 0.25);
CGContextSetFillColorWithColor(context, alternateColor);
CGContextAddRect(context, CGRectMake(0.0f, 0.0f, kCheckerboardSize, kCheckerboardSize));
CGContextFillPath(context);
CGContextAddRect(context, CGRectMake(kCheckerboardSize, kCheckerboardSize, kCheckerboardSize, kCheckerboardSize));
CGContextFillPath(context);
CGColorRelease(alternateColor);
}
- (void)drawLayer:(CALayer *)layer inContext:(CGContextRef)context
{
CGFloat red = 0.0f, green = 0.0f, blue = 0.0f, alpha = 0.0f;
NSColor *originalBackgroundColor = [self.document.backgroundColor colorUsingColorSpaceName:NSCalibratedRGBColorSpace];
[originalBackgroundColor getRed:&red green:&green blue:&blue alpha:&alpha];
CGColorRef bgColor = CGColorCreateGenericRGB(red, green, blue, alpha);
CGContextSetFillColorWithColor(context, bgColor);
CGContextFillRect(context, layer.bounds);
// Should we draw a checkerboard pattern?
if([self.document.drawCheckerboard boolValue])
{
static const CGPatternCallbacks callbacks = { 0, &drawCheckerboardPattern, NULL };
CGContextSaveGState(context);
CGColorSpaceRef patternSpace = CGColorSpaceCreatePattern(NULL);
CGContextSetFillColorSpace(context, patternSpace);
CGColorSpaceRelease(patternSpace);
CGPatternRef pattern = CGPatternCreate(NULL,
CGRectMake(0.0f, 0.0f, kCheckerboardSize*2, kCheckerboardSize*2),
CGAffineTransformIdentity,
kCheckerboardSize*2,
kCheckerboardSize*2,
kCGPatternTilingConstantSpacing,
true,
&callbacks);
alpha = 1.0f;
CGContextSetFillPattern(context, pattern, &alpha);
CGPatternRelease(pattern);
CGContextFillRect(context, layer.bounds);
CGContextRestoreGState(context);
}
CGColorRelease(bgColor);
}
You can create the pattern outside your
drawLayer:inContext:just fine, it doesn’t need a context. So just create aCGPatternRefinstance variable and create the pattern. That should already speed up rendering as creating the pattern is expensive. In fact, I would create allCG*instances that don’t need a context outside yourdrawLayer:inContext:method, so everything up toCGColorCreateGenericRGBand also theCGColorSpaceCreatePattern.