Batch Processing for Graphics

You can see why effective Windows NT programming largely is about managing the batch of calls routed to CSRSS. Making sure this batch is as large as possible, when appropriate, is the goal.

When is it not appropriate? When you need the display to immediately reflect the drawing you do, you want to flush the batch explicitly no matter how large or small it is. Performance Monitor does this as soon as it has updated the display with a new chart data point. Failing to do this causes the data to be updated with noticeably odd timing. Also, you want to minimize the batch when you are debugging your application. Otherwise, an error returned to an application programming interface (API) call in the middle of a batch may not be returned until some other call flushes the batch; it will appear then that the wrong call failed. This seems pretty serious until you learn that debugged applications cannot get failures on API calls which can be batched. This is one of the criteria the system designers used for determining if an API can be batched. Finally, if you are doing certain performance measurements on your application, you will want to set the batch to one. We'll discuss this in the next chapter.

In general, you can batch graphical output functions that return a Boolean value indicating success or failure. A few frequently used APIs that return non-Boolean results which were seldom used have new replacement calls that just return Boolean results. SetPixelV and MoveToEx are the new calls in two important cases. (Remember this: there will be a test later.)

Three new API calls help you manage the batch. They are all optional; the default works fine except in rather odd cases, such as Performance Monitor updating a display in real time. GdiSetBatchLimit allows you to raise and lower the batch limit which, as we mentioned, defaults to ten. For best performance, you should set the limit as high as possible while avoiding jerky drawing on the display. You will want to test any changes to the batch limit on a very slow machine and a very fast one to be sure you have not introduced a problem which will only appear in one environment or the other. You can call GdiGetBatchLimit to determine the current limit. And you can call GdiFlush to flush the batch to CSRSS at the end of an operation you would like to see displayed immediately.

Most calls that manipulate the window system flush the batch. One reason is that much of the window system is visible to all processes on the desktop and so the central data repository for the common information is within CSRSS. We mentioned that PeekMessage does not flush the batch, but GetMessage does. So do graphics calls that return a handle or a number. An important exception to this is the group of calls for selecting fonts, brushes, and pens. These are batched. But selecting bitmaps and regions flush the batch. So do SetWorldTransform and SetMapMode. We are telling you all this so that (when possible) you will try to organize your code to group graphical calls together, and then make the calls that flush the batch.

Another way to reduce the overhead for the client-server architecture is to write your application to take advantage of the several calls beginning with "Poly." These exploit the fact that many drawing calls use identical attributes, and so multiple items can be drawn in a single call once the brushes, pens, colors, and fonts have been selected. Whenever possible be sure to use PolyTextOut, PolyPolyline, PolylineTo, PolyDraw, PolyBezier and PolyBezierTo. The Windows NT console window uses PolyTextOut. This change reduced scrolling time in a console window by 30% when it was implemented during the development of Windows NT.