programing

UIBezierPath가 Core Graphics 경로보다 빠른 이유는 무엇입니까?

nasanasas 2020. 9. 14. 21:15
반응형

UIBezierPath가 Core Graphics 경로보다 빠른 이유는 무엇입니까?


그리기 경로를 가지고 놀았는데, 적어도 어떤 경우에는 UIBezierPath가 Core Graphics와 동등하다고 생각했던 것보다 성능이 뛰어납니다. -drawRect:하나 UIBezierPath, 하나 CGPath : 방법에 대하여 두 가지의 경로를 생성한다. 경로는 위치를 제외하고는 동일하지만 CGPath를 입력하는 데는 UIBezierPath를 입력하는 것보다 약 두 배가 걸립니다.

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Create the two paths, cgpath and uipath.
    CGMutablePathRef cgpath = CGPathCreateMutable();
    CGPathMoveToPoint(cgpath, NULL, 0, 100);

    UIBezierPath *uipath = [[UIBezierPath alloc] init];
    [uipath moveToPoint:CGPointMake(0, 200)];

    // Add 200 curve segments to each path.
    int iterations = 200;
    CGFloat cgBaseline = 100;
    CGFloat uiBaseline = 200;
    CGFloat xincrement = self.bounds.size.width / iterations;
    for (CGFloat x1 = 0, x2 = xincrement;
         x2 < self.bounds.size.width;
         x1 = x2, x2 += xincrement)
    {
        CGPathAddCurveToPoint(cgpath, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, cgBaseline);
        [uipath addCurveToPoint:CGPointMake(x2, uiBaseline)
                  controlPoint1:CGPointMake(x1, uiBaseline-50)
                  controlPoint2:CGPointMake(x2, uiBaseline+50)];
    }
    [[UIColor blackColor] setStroke];
    CGContextAddPath(ctx, cgpath);

    // Stroke each path.
    [self strokeContext:ctx];
    [self strokeUIBezierPath:uipath];

    [uipath release];
    CGPathRelease(cgpath);
}

- (void)strokeContext:(CGContextRef)context
{
    CGContextStrokePath(context);
}

- (void)strokeUIBezierPath:(UIBezierPath*)path
{
    [path stroke];
}

두 경로 모두 CGContextStrokePath ()를 사용하므로 Instruments의 각 경로에서 사용하는 시간을 볼 수 있도록 각 경로를 스트로크하는 별도의 메서드를 만들었습니다. 다음은 일반적인 결과입니다 (호출 트리 반전). 당신은이 볼 수있는 -strokeContext:9.5 초 걸린다., 동안 -strokeUIBezierPath:5 초 걸립니다 :

Running (Self)      Symbol Name
14638.0ms   88.2%               CGContextStrokePath
9587.0ms   57.8%                 -[QuartzTestView strokeContext:]
5051.0ms   30.4%                 -[UIBezierPath stroke]
5051.0ms   30.4%                  -[QuartzTestView strokeUIBezierPath:]

It looks like UIBezierPath is somehow optimizing the path that it creates, or I'm creating the CGPath in a naïve way. What can I do to speed up my CGPath drawing?


You are correct in that UIBezierPath is simply an objective-c wrapper for Core Graphics, and therefore will perform comparably. The difference (and reason for your performance delta) is your CGContext state when drawing your CGPath directly is quite different to that setup by UIBezierPath. If you look at UIBezierPath, it has settings for:

  • lineWidth,
  • lineJoinStyle,
  • lineCapStyle,
  • miterLimit and
  • flatness

When examining the call (disassembly) to [path stroke], you will note that it configures the current graphic context based on those previous values before performing the CGContextStrokePath call. If you do the same prior to drawing your CGPath, it will perform the same:

- (void)drawRect:(CGRect)rect
{
    CGContextRef ctx = UIGraphicsGetCurrentContext();

    // Create the two paths, cgpath and uipath.
    CGMutablePathRef cgpath = CGPathCreateMutable();
    CGPathMoveToPoint(cgpath, NULL, 0, 100);

    UIBezierPath *uipath = [[UIBezierPath alloc] init];
    [uipath moveToPoint:CGPointMake(0, 200)];

    // Add 200 curve segments to each path.
    int iterations = 80000;
    CGFloat cgBaseline = 100;
    CGFloat uiBaseline = 200;
    CGFloat xincrement = self.bounds.size.width / iterations;
    for (CGFloat x1 = 0, x2 = xincrement;
         x2 < self.bounds.size.width;
         x1 = x2, x2 += xincrement)
    {
        CGPathAddCurveToPoint(cgpath, NULL, x1, cgBaseline-50, x2, cgBaseline+50, x2, cgBaseline);
        [uipath addCurveToPoint:CGPointMake(x2, uiBaseline)
                  controlPoint1:CGPointMake(x1, uiBaseline-50)
                  controlPoint2:CGPointMake(x2, uiBaseline+50)];
    }
    [[UIColor blackColor] setStroke];
    CGContextAddPath(ctx, cgpath);

    // Stroke each path
    CGContextSaveGState(ctx); {
        // configure context the same as uipath
        CGContextSetLineWidth(ctx, uipath.lineWidth);
        CGContextSetLineJoin(ctx, uipath.lineJoinStyle);
        CGContextSetLineCap(ctx, uipath.lineCapStyle);
        CGContextSetMiterLimit(ctx, uipath.miterLimit);
        CGContextSetFlatness(ctx, uipath.flatness);
        [self strokeContext:ctx];
        CGContextRestoreGState(ctx);
    }
    [self strokeUIBezierPath:uipath];

    [uipath release];
    CGPathRelease(cgpath);
}

- (void)strokeContext:(CGContextRef)context
{
    CGContextStrokePath(context);
}

- (void)strokeUIBezierPath:(UIBezierPath*)path
{
    [path stroke];
}

Snapshot from Instruments: Instruments snapshot showing equal performance

참고URL : https://stackoverflow.com/questions/6327817/why-is-uibezierpath-faster-than-core-graphics-path

반응형