1. With Quartz, you "draw into" 1 of 2 things: either:
a) CGContextRef
this is like a window, or a PDF document, or similar.
I think of it as a window.
b) CGBitmapContextRef
this is like a gworld. a bitmap buffer.
In Quartz, you draw into a CGContext. (end of sentence).
CGContexts can be attached to a number of different devices. For
example, you can get a CGContext that allows you to draw to a window,
or a context for drawing on a printer. You can create contexts for
saving graphics to PDF files. Some contexts draw to devices that
have pixel buffers associated with them (like a window), and some
draw to devices that do not have pixel buffers (like a PDF file).
One particularly important drawing destination that is frequently
used in applications is the offscreen pixel buffer. To draw into an
offscreen pixel buffer using Quartz 2D, your application can create a
CGBitmapContext that is connected to that pixel buffer. This is a
CGContext, like any other CGContext, but it's drawing destination
just happens to be a pixel-based device, and you own the pixels.
2. In QD, you could "jump" between a window and a gworld
using CopyBits. Draw to the screen directly, and the CopyBits
the bitmap over to a Gworld, or vice versa (usually vice versa, but
not always).
In QuickDraw, the CopyBits routine allows you to copy data between
two pixel maps. Most of the time, those pixel maps were the drawing
destinations of a CGrafPort. CopyBits, therefore, was a handy tool
for transferring pixels from one CGrafPort to another. This included
copying pixels from an offscreen GWorld to a window.
Unfortunately, not all CGContexts have pixel buffers associated with
them. There is, therefore, no equivalent to CopyBits in Quartz 2D.
It doesn't make sense, for example, to try and "CopyBits" from a PDF
context to a window because the PDF context doesn't have any pixels
to copy.
In Quartz, no more CopyBits, so you have to think ahead. If you are
every going to want those bits for anything, you had better write
them into a CGBitmapContextRef first.
The abstraction you use in Quartz 2D to draw pixel-based structures
is a CGImage. While your CGBitmapContext will allow you to use
Quartz 2D to draw into a pixel buffer, in order to draw those pixels
on another graphics context, you are going to have to create a
CGImage from the pixels and draw that CGImage on the destination context
Once you draw to a CGContextRef (i.e. a window), it's gone.
If you draw your graphics into an offscreen pixel buffer using a
CGBitmapContext, you will be able to retrieve the pixels you have
drawn because you own the pixel buffer. In general, when working
with CGContexts, this is not the case.
(note: you can draw into a CGContextRef until you run out of
electrons, but
you won't see anything with your eyes until you do a CGContextFlush
(unless you're
playing with compositing windows and such)).
You should rarely find the need to call CGContextFlush.
Instead, your application should draw in response to update events
from the appropriate application framework. The framework will decide
when to flush drawing forward. If you need to force one of your views
to redraw, you should use HIViewSetNeedsDisplay in Carbon, or
setNeedsDisplayInRect: (et al.) in Cocoa to ask the framework to send
you an update event and perform your drawing in response.
In the rare instance that you have found yourself in a loop that is
not passing control back to the main event loop as it should, or if
you have a specific need for an intermediate drawing to be flushed to
the display, then you may have to call CGContextFlush.
If you are in that situation, however, you should be careful to
ensure that you are not calling CGContextFlush too often. Anything
more than approximately 60 times a second could be a bad performance
sink. You may end up blocking your application excessively and
starving it of CPU time.
3. Some Quartz drawing commands are deadly on speed. Unless
you're printing
(or making a PDF), never stroke a path when you can just fill it.
StrokePath does all
kinds of intersection tests on the path so the PDF stuff comes out
perfect; but for
screen drawing and refreshing on anything complicated, it will
bring your app
to its knees. Figure out the "bounding path" for a given path,
and fill it. Silly,
I know it sounds, but ...
If you are stroking a very complex path, one that has lots of self-
intersections, and you are drawing it to a bitmap context with
antialiasing enabled, then the self-intersection tests needed to
correctly antialias the path during rasterization can be rather
expensive. However, this will also be true if you have a very complex
polygon, with lots of self intersections, and you ask the computer to
fill it.
This situation should come up rather infrequently. Certainly not
frequently enough to pass some sort of injunctive statements against
stroking paths. In these cases, you may get better performance by
splitting the complex, single path, into smaller individual paths
that can be stroked, or filled independently.
The performance issue is not evident in PDF drawing (or printing,
which is largely the same operation) because the PDF context has no
pixels, is not antialiased, and there is no need to perform the self
intersection calculations at the generating application's end.
Depending on the output device, however, drawing that PDF may incur
the same kind of performance issues and you would be better off
splitting up the complex path if possible in that instance as well.
Similarly, cacheing to a CGBitmapContextRef (and either saving the
CGBitmapContextRef
or the CGImageRef you make from it) is essential for speed - if you
needed to do this in QD for your app, you probably need to do the
same in Quartz.
I would advise trying to draw the graphics with Quartz first, and
only jump to Quartz 2D if performance proves to be unacceptable.
For example, offscreen pixel buffers, particularly large,
uncompressed offscreen pixel buffers, take up quite a lot of
memory. The more memory your application uses, the more time the
system will spend paging that memory in and out. Paging memory is
MUCH slower than drawing simple graphics with Quartz 2D.
This is particularly true if you are drawing to the display screen
(i.e. to a window). The system can optimize the Quartz 2D graphics
path much more efficiently for drawing commands (drawing paths) than
it can for drawing large pixel buffers. There's a good chance those
large pixel buffers will have to be moved to VRAM at some point and
shipping large pixel buffers over the graphics bus can be taxing.
_______________________________________________
Do not post admin requests to the list. They will be ignored.
Quartz-dev mailing list (email@hidden)
Help/Unsubscribe/Update your Subscription:
http://lists.apple.com/mailman/options/quartz-dev/email@hidden