• Open Menu Close Menu
  • Apple
  • Shopping Bag
  • Apple
  • Mac
  • iPad
  • iPhone
  • Watch
  • TV
  • Music
  • Support
  • Search apple.com
  • Shopping Bag

Lists

Open Menu Close Menu
  • Terms and Conditions
  • Lists hosted on this site
  • Email the Postmaster
  • Tips for posting to public mailing lists
Re: Cocoa graphics speed
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Cocoa graphics speed


  • Subject: Re: Cocoa graphics speed
  • From: Chris Hanson <email@hidden>
  • Date: Mon, 29 Sep 2003 17:18:09 -0500

There are substantial differences in the graphics architectures between QuickDraw and CoreGraphics.

In QuickDraw, you're always working in pixel coordinates. In the worst case, your coordinates have to be translated from port to global coordinates, and then your rectangle can be filled.

In CoreGraphics, you're always working in an abstract "user space." Coordinates in user space are mapped to device space via the concatenation of two translation matrices; they're mapped from user space to ideal space (with 72 points per inch) by the current transformation matrix (CTM) and from ideal space to device space via another matrix. Right now, in CoreGraphics, when drawing to the screen ideal and device space are the same thing. But they don't have to be, and aren't when printing.

OK, so instead of one simple addition per coordinate for your rectangle, you have a matrix multiply. That costs a bit right there, but it gets you a *lot* of flexibility.

There's even more to filling a "simple" rectangle in CoreGraphics though. QuickDraw will fill your rectangle with a simple pattern. CoreGraphics patterns are much more complex -- there's a lot more they can do. CoreGraphics cares about And in QuickDraw, you're fundamentally just setting bits; in CoreGraphics, you aren't, you're creating paths, filling them, and then throwing them away.

Essentially, an implementation of NSRectFill looks something like this:

void NSRectFill(NSRect rect) {
NSBezierPath *path = [NSBezierPath bezierPathWithRect:rect];
[path fill];
}

It's creating a path, filling it, and then tossing it out. That's expensive.

One way to speed up your code would be to create a real NSBezierPath for the rectangle, and keep the path itself around. You can then replace your NSRectFill(ptRect) with something like this:

[cachedPath removeAllPoints];
[cachedPath appendBezierPathWithRect:ptRect];
[cachedPath fill];

Another thing you could do is keep a unit square path around, and then just scale & translate the coordinate system as necessary before filling your unit square path. That's what's happening behind the scenes anyway; you could "cut out the middleman" and only do the work you really need to do by going that route. I'm not sure whether or not that'd be faster, but it might since all you'd be doing is manipulating the CTM.

Another thing you should definitely do to speed up your code is only draw those portions of your view that actually need to be redrawn. Do an intersection test with the rectangle passed to your view's -drawRect: method, and only draw those that intersect with it. Also, be careful not to use -setNeedsDisplay: but rather -setNeedsDisplayInRect: to tell the AppKit that a view needs to be refreshed. That will let the AppKit determine the optimal rectangle to update; it won't try to update everything all the time. This would probably require that your elements keep track of their own radius, rather than asking the sender of -stroke:; either that, or the sender of -stroke: should also keep track of the current rectangle passed to -drawRect: and allow your elements to look at it to determine whether they need to be drawn.

I hope this gives you some idea as to why what you're doing has different performance characteristics with Cocoa/CoreGraphics and QuickDraw, and gives you some strategies for ways you can optimize your drawing.

CoreGraphics does a *lot* more than QuickDraw and is quite a nice architecture, but it's not without its costs.

-- Chris

PS - To the CG-experienced Cocoa developers out there, is there a lower-level CoreGraphics equivalent to the -[NSBezierPath bounds] method that only gets the path's bounds, rather than its bounds including control points (which one can get by using -[NSBezierPath controlPointBounds])? Some developers were asking how to do this over on Apple's Carbon-Development mailing list.

--
Chris Hanson, bDistributed.com, Inc. | Email: email@hidden
Custom Mac OS X Development | Phone: +1-847-372-3955
http://bdistributed.com/ | Fax: +1-847-589-3738
http://bdistributed.com/Articles/ | Personal Email: email@hidden
_______________________________________________
cocoa-dev mailing list | email@hidden
Help/Unsubscribe/Archives: http://www.lists.apple.com/mailman/listinfo/cocoa-dev
Do not post admin requests to the list. They will be ignored.

  • Follow-Ups:
    • Re: Cocoa graphics speed
      • From: "Alastair J.Houghton" <email@hidden>
References: 
 >Cocoa graphics speed (From: John Nairn <email@hidden>)

  • Prev by Date: Re: CustomView and nib file
  • Next by Date: Re: Cocoa graphics speed
  • Previous by thread: Cocoa graphics speed
  • Next by thread: Re: Cocoa graphics speed
  • Index(es):
    • Date
    • Thread