129 lines
9.4 KiB
HTML
129 lines
9.4 KiB
HTML
<HTML>
|
|
<HEAD>
|
|
<META name=vsisbn content="1576101746">
|
|
<META name=vstitle content="Michael Abrash's Graphics Programming Black Book, Special Edition">
|
|
<META name=vsauthor content="Michael Abrash">
|
|
<META name=vspublisher content="The Coriolis Group">
|
|
<META name=vspubdate content="07/01/97">
|
|
<META name=vscategory content="Web and Software Development: Game Development,Web and Software Development: Graphics and Multimedia Development">
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<TITLE>Michael Abrash's Graphics Programming Black Book Special Edition: Dog Hair and Dirty Rectangles</TITLE>
|
|
|
|
<!-- HEADER -->
|
|
<!-- Empty Reference Subhead -->
|
|
|
|
<!--ISBN=1576101746//-->
|
|
<!--TITLE=Michael Abrash's Graphics Programming Black Book Special Edition//-->
|
|
<!--AUTHOR=Michael Abrash//-->
|
|
<!--PUBLISHER=The Coriolis Group, Inc.//-->
|
|
<!--CHAPTER=45//-->
|
|
<!--PAGES=843-846//-->
|
|
<!--UNASSIGNED1//-->
|
|
<!--UNASSIGNED2//--></HEAD><BODY LINK=#0000FF ALINK=#000099 VLINK=#0000FF BGCOLOR=#FFFFFF>
|
|
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="45-01.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="45-03.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
<P><BR></P>
|
|
<P>Of course, VGA display memory has its own performance problems. The fastest ISA bus VGA can, at best, support sustained write times of about 10 cycles per word-sized write on a 486/33; 15 or 20 cycles is more common, even for relatively fast SuperVGAs; the worst case I’ve seen is 65 cycles per byte. However, intermittent writes, mixed with a lot of register and cache-only code, can effectively execute in one cycle, thanks to the caching design of many VGAs and the 486’s 4-deep write buffer, which stores pending writes while the CPU continues executing instructions. Display memory reads tend to take longer, because coprocessing isn’t possible—one microsecond is a reasonable rule of thumb for VGA reads, although there’s considerable variation. So VGA memory tends not to be as bad as VGA I/O, but lord knows it isn’t <I>good</I>.</P>
|
|
<TABLE WIDTH="100%"><TR>
|
|
<TD COLSPAN="4"><HR>
|
|
<TR>
|
|
<TD WIDTH "40%" VALIGN="TOP" ALIGN="LEFT">
|
|
<TH ALIGN="CENTER" COLSPAN="3">OUT Time in Microseconds and Cycles
|
|
<TR>
|
|
<TH WIDTH="40%" ALIGN="LEFT" VALIGN="BOTTOM">OUT Instruction
|
|
<TH WIDTH="20%" ALIGN="LEFT" VALIGN="BOTTOM">Official Time
|
|
<TH WIDTH="20%" ALIGN="LEFT" VALIGN="BOTTOM">486 #1/16-bit VGA #1
|
|
<TH WIDTH="20%" ALIGN="LEFT" VALIGN="BOTTOM">486 #2/16-bit VGA #2
|
|
<TR>
|
|
<TD COLSPAN="4"><HR>
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">OUT DX,AL
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">repeated 1,000 times nonstop<BR>(maximum byte access)
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">0.300 s<BR>10 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">2.546 s<BR>84 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">0.813 s<BR>27 cycles
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">OUT DX,AX
|
|
<TR>
|
|
<TD WIDTH="4%" VALIGN="TOP" ALIGN="LEFT">repeated 1,000 times nonstop<BR>(maximum word access)
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">0.300 s<BR>10 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">3.820 s<BR>126 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">1.066 s<BR>35 cycles
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">OUT DX,AL
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">repeated 1,000 times,<BR>but interspersed with MULs<BR>(random byte access)
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">0.300 s<BR>10 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">1.610 s<BR>53 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">0.780 s<BR>26 cycles
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">OUT DX,AX
|
|
<TR>
|
|
<TD WIDTH="40%" VALIGN="TOP" ALIGN="LEFT">repeated 1,000 times,<BR>but interspersed with MULs<BR>(random word access)
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">0.300 s<BR>10 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">2.830 s<BR>93 cycles
|
|
<TD WIDTH="20%" VALIGN="TOP" ALIGN="LEFT">1.010 s<BR>33 cycles
|
|
<TR>
|
|
<TD COLSPAN="4"><B>Table 45.1 Results of I/O performance tests run under the Phar Lap386|DOS-Extender.
|
|
<TR>
|
|
<TD COLSPAN="4"><HR>
|
|
</TABLE>
|
|
<P>
|
|
</P>
|
|
<TABLE WIDTH="100%"><TR>
|
|
<TD VALIGN="TOP" ALIGN="LEFT" WIDTH="5%"><IMG SRC="images/45-01i.jpg"><TD VALIGN="TOP" ALIGN="LEFT" WIDTH="95%"><SMALL><I><B>OUT</B>s, in general, are lousy on the 486 (and to think they only took three cycles on the 286!). <B>OUT</B>s to VGAs are particularly lousy. Display memory performance is pretty poor, especially for reads. The conclusions are obvious, I would hope. Structure your graphics code, and, in general, all 486 code, to avoid <B>OUT</B>s.</I></SMALL>
|
|
</TABLE>
|
|
<P>For graphics, this especially means using write mode 3 rather than the bit-mask register. When you must use the bit mask, arrange drawing so that you can set the bit mask once, then do a lot of drawing with that mask. For example, draw a whole edge at once, then the middle, then the other edge, rather than setting the bit mask several times on each scan line to draw the edge and middle bytes together. Don’t read from display memory if you don’t have to. Write each pixel once and only once.
|
|
</P>
|
|
<P>It is indeed a strange concept: The key to fast graphics is staying away from the graphics adapter as much as possible.</P>
|
|
<H3><A NAME="Heading5"></A><FONT COLOR="#000077">Dirty-Rectangle Animation</FONT></H3>
|
|
<P>The relative slowness of VGA hardware is part of the appeal of the technique that I call “dirty-rectangle” animation, in which a complete copy of the contents of display memory is maintained in offscreen system (nondisplay) memory. All drawing is done to this system buffer. As offscreen drawing is done, a list is maintained of the bounding rectangles for the drawn-to areas; these are the <I>dirty rectangles</I>, “dirty” in the sense that that have been altered and no longer match the contents of the screen. After all drawing for a frame is completed, all the dirty rectangles for that frame are copied to the screen in a burst, and then the cycle of off-screen drawing begins again.</P>
|
|
<P>Why, exactly, would we want to go through all this complication, rather than simply drawing to the screen in the first place? The reason is visual quality. If we were to do all our drawing directly to the screen, there’d be a lot of flicker as objects were erased and then redrawn. Similarly, overlapped drawing done with the painter’s algorithm (in which farther objects are drawn first, so that nearer objects obscure them) would flicker as farther objects were visible for short periods. With dirty-rectangle animation, only the finished pixels for any given frame ever appear on the screen; intermediate results are never visible. Figure 45.1 illustrates the visual problems associated with drawing directly to the screen; Figure 45.2 shows how dirty-rectangle animation solves these problems.</P>
|
|
<P><A NAME="Fig1"><!-- </A><A HREF="javascript:displayWindow('images/45-01.jpg',409,160 )"> --><IMG SRC="images/45-01.jpg"><BR><!-- </A>
|
|
<BR><A HREF="javascript:displayWindow('images/45-01.jpg',409,160)"> --><FONT COLOR="#000077"><B>Figure 45.1</B></FONT></A> <I>Drawing directly to the screen.</I>
|
|
</P>
|
|
<P><A NAME="Fig2"><!-- </A><A HREF="javascript:displayWindow('images/45-02.jpg',411,301 )"> --><IMG SRC="images/45-02.jpg"><BR><!-- </A>
|
|
<BR><A HREF="javascript:displayWindow('images/45-02.jpg',411,301)"> --><FONT COLOR="#000077"><B>Figure 45.2</B></FONT></A> <I>Dirty rectangle animation.</I>
|
|
</P>
|
|
<H4 ALIGN="LEFT"><A NAME="Heading6"></A><FONT COLOR="#000077">So Why Not Use Page Flipping?</FONT></H4>
|
|
<P>Well, then, if we want good visual quality, why not use page flipping? For one thing, not all adapters and all modes support page flipping. The CGA and MCGA don’t, and neither do the VGA’s 640×480 16-color or 320×200 256-color modes, or many SuperVGA modes. In contrast, <I>all</I> adapters support dirty-rectangle animation. Another advantage of dirty-rectangle animation is that it’s generally faster. While it may seem strange that it would be faster to draw off-screen and then copy the result to the screen, that is often the case, because dirty-rectangle animation usually reduces the number of times the VGA’s hardware needs to be touched, especially in 256-color modes.</P>
|
|
<P>This reduction comes about because when dirty rectangles are erased, it’s done in system memory, not in display memory, and since most objects move a good deal less than their full width (that is, the new and old positions overlap), display memory is written to fewer times than with page flipping. (In 16-color modes, this is not necessarily the case, because of the parallelism obtained from the VGA’s planar hardware.) Also, read/modify/write operations are performed in fast system memory rather than slow display memory, so display memory rarely needs to be read. This is particularly good because display memory is generally even slower for reads than for writes.</P><P><BR></P>
|
|
<CENTER>
|
|
<TABLE BORDER>
|
|
<TR>
|
|
<TD><A HREF="45-01.html">Previous</A></TD>
|
|
<TD><A HREF="index.html">Table of Contents</A></TD>
|
|
<TD><A HREF="45-03.html">Next</A></TD>
|
|
</TR>
|
|
</TABLE>
|
|
</CENTER>
|
|
|
|
<hr width="90%" size="1" noshade>
|
|
<div align="center">
|
|
<font face="Verdana,sans-serif" size="1">Graphics Programming Black Book © 2001 Michael Abrash</font>
|
|
</div>
|
|
<!-- all of the reference materials (books) have the footer and subfoot reveresed -->
|
|
<!-- reference_subfoot = footer -->
|
|
<!-- reference_footer = subfoot -->
|
|
|
|
<!-- BEGIN SUB FOOTER -->
|
|
</BODY>
|
|
</HTML>
|
|
|
|
<!-- END FOOTER -->
|
|
|
|
|