home *** CD-ROM | disk | FTP | other *** search
/ InfoMagic Source Code 1993 July / THE_SOURCE_CODE_CD_ROM.iso / X / mit / doc / Server / strat.ms < prev    next >
Encoding:
Text File  |  1991-05-04  |  74.7 KB  |  1,891 lines

  1. .EF 'Strategies for Porting'- % -'March 1, 1988'
  2. .OF 'Strategies for Porting'- % -'March 1, 1988'
  3. .EH '''
  4. .OH '''
  5. .TL
  6. Strategies for Porting
  7. the X v11 Sample Server
  8. .AU
  9. Susan Angebranndt
  10. .AU
  11. Raymond Drewry
  12. .AU
  13. Philip Karlton
  14. .AU
  15. Todd Newman
  16. .AI
  17. Digital Equipment Corporation
  18. .AI
  19. minor revisions by
  20. .AU
  21. Bob Scheifler
  22. .AI
  23. Massachusetts Institute of Technology
  24. .AI
  25. Revised for Release 4 and Release 5 by
  26. .AU
  27. Keith Packard
  28. .AI
  29. MIT X Consortium
  30.  
  31. .LP
  32. X is a graphic user interface system enabling an application
  33. program to run on a computer other than the user's workstation.
  34. A "display server" (or simply "server") is the user's workstation.
  35. A "client" is an application program running on a machine 
  36. with which the user interacts.
  37. Accompanying this document is the X Window System source tape,
  38. which also contains the "Definition
  39. of the Porting Layer" document.
  40.  
  41. This document is a guide to porting the X server
  42. software to your workstation.
  43.  
  44. .IP 1)
  45. Read the first section of this document (Overview of Porting Process).
  46. It describes what you will go through.
  47.  
  48. .IP 2)
  49. Skim the "Definition of the Porting Layer" document.
  50.  
  51. .IP 3)
  52. Scan the Details section of this document.
  53.  
  54. .IP 4)
  55. Start planning and working, referring to the Strategies
  56. and Definition documents.
  57.  
  58. You may also want to look at the following documents:
  59. .IP \(bu 5
  60. "The X Window System"
  61. for an overview of X.
  62. .IP \(bu 5
  63. "Xlib - C Language X Interface"
  64. for a view of what the client programmer sees.
  65. .IP \(bu 5
  66. "X Window System Protocol"
  67. for a terse description of the bytestream protocol
  68. between the client and server.
  69. .IP \(bu 5
  70. "X11 Server Extensions Engineering Specification"
  71. for a description of how to add features to your X server
  72. in an agreeable way.
  73.  
  74. UNIX is a trademark of AT&T.
  75. QVSS, LK201, ULTRIX, VMS, DEC, MicroVAX and 
  76. VAX are trademarks of Digital Equipment Corporation.
  77. Macintosh and Apple are trademarks of Apple Computer, Inc.
  78. PostScript is a trademark of Adobe Systems, Inc.
  79. Ethernet is a trademark of Xerox Corporation.
  80. X and the X Window System are trademarks of 
  81. Massachusetts Institute of Technology.
  82. Cray is a trademark of Cray Research, Inc.
  83.  
  84. .NH 1
  85. Overview of the Porting Process
  86. .XS
  87. Overview of the Porting Process
  88. .XE
  89. .NH 2
  90. Directories
  91. .XS
  92. Directories
  93. .XE
  94. .LP
  95. This section describes some of the directories accompanying the tape.
  96. .LP
  97. lib/X
  98. .RS
  99. .RE
  100. The X client library is used for developing client programs.
  101. Since it is simple and straightforward, it should be very easy to port.
  102.  
  103. .LP
  104. doc/
  105. .RS
  106. .RE
  107. This directory contains documentation, such as an online copy of this document
  108. and the others mentioned.
  109. .LP
  110. Makefile
  111. .RS
  112. .RE
  113. This is a master make file for everything on the tape.
  114.  
  115. .LP
  116. fonts/
  117. .RS
  118. .RE
  119. This directory has font files in a text format and the compiler
  120. to compile them into a binary format that your server uses.
  121.  
  122. .LP
  123. fonts/lib
  124. .RS
  125. .RE
  126. This directory contains a library of routines for handling fonts.  It
  127. contains all of the interfaces used by both the X and Font servers.  It also
  128. contains routines for manipulating font files which are used by bdftopcf and
  129. mkfontdir.
  130.  
  131. .LP
  132. fonts/bdf
  133. .RS
  134. .RE
  135. This directory contains directories of font files.
  136. The font files are in a text format called "bdf." (See the 
  137. "Definition of the Porting Layer" document, section 5.2.8.)
  138. There are three sections:  misc, 75dpi and 100dpi.  The misc
  139. directory contains fonts which do not fit a particular resolution; the
  140. cursor font, various fixed-pixel-size fonts and fonts which are needed
  141. by various toolkits for icon images.  75dpi and 100dpi contain identical
  142. font sets at 75 dots-per-inch and 100 dots-per-inch respectively.  All of
  143. these fonts conform to the XLFD standard; most of them are in ISO-8859-1
  144. (Latin-1) encoding.
  145.  
  146. .LP
  147. fonts/tools/bdftopcf
  148. .RS
  149. .RE
  150. This directory has the font compiler source.
  151. The old bdftosnf compiler had private definitions for the glyph format;
  152. bdftopcf inherits the definitions from the server so special configuration
  153. is not needed here.  Besides, if you get it wrong, the server will still
  154. run, but will spend quite a bit of time reformating the fonts.
  155.  
  156. .LP
  157. fonts/tools/mkfontdir
  158. .RS
  159. .RE
  160. mkfontdir is run over a directory containing font files.  It produces
  161. the database which the server uses to map font-names to file-names.
  162.  
  163. .LP
  164. X11/
  165. .RS
  166. .RE
  167. This is an important directory because it has some include files
  168. that are actually shared between client (Xlib) and server, such as
  169. X.h, Xproto.h.  The files in this directory are actually installed from
  170. include/ during the initial build process.
  171.  
  172. .LP
  173. server/
  174. .RS
  175. .RE
  176. This directory
  177. contains all the source for the server code.
  178. There are some other files that are needed from other top-level directories,
  179. such as .h files from the X11/ directory.
  180.  
  181. .LP
  182. server/ddx
  183. .RS
  184. .RE
  185. This directory has all the Device Dependent X server code.
  186. Operating System dependent code is under server/os.
  187.  
  188. .LP
  189. server/ddx/cfb
  190. .RS
  191. .RE
  192. This directory has "Pixblit" and other 
  193. code for Color Frame Buffer displays.
  194. (In this document, "color" means multiple bits per pixel.
  195. You may be able to simply plug in a few
  196. special numbers into defines, then compile it and have it work for your
  197. display.
  198. Otherwise, it will serve as no more than an example of what you should
  199. implement as Pixblit routines for your own frame buffer.
  200.  
  201. .LP
  202. server/ddx/mfb
  203. .RS
  204. .RE
  205. This directory has "Pixblit" and other 
  206. code for Monochrome Frame Buffer displays.
  207. (In this document, "monochrome" means a black and white display with
  208. one bit per pixel.
  209. Even though the usual meaning of monochrome is more general, this special
  210. case is so common that we decided to reserve the word for this purpose.)
  211. If you have a monochrome screen, you may be able to simply plug in a few
  212. special numbers into defines, then compile it and have it work for your
  213. display.
  214. Otherwise, it will serve as no more than an example of what you should
  215. implement as Pixblit routines for your own frame buffer.
  216.  
  217. .LP
  218. server/ddx/mi
  219. .RS
  220. .RE
  221. This directory contains Machine Independent DDX code.
  222. It supplies the "Drawing Primitive" procedures that DIX calls
  223. to perform graphics and calls the "Pixblit routines."
  224. It also contains other routines.
  225. It is portable to any system that can draw graphics by
  226. manipulating rows of pixels by hand.
  227. See the "Definition" document for an explanation of these terms.
  228.  
  229. .LP
  230. server/ddx/apollo,dec,hp,ibm,macII,mips,sun,tek
  231. .RS
  232. .RE
  233. These directories contain device-specific code which runs
  234. on a wide variety of machines.  All of these directories
  235. were, at least originally, contributed by the various hardware vendors.
  236. None of them represent actual production code entirely.
  237.  
  238. .LP
  239. server/dix
  240. .RS
  241. .RE
  242. This is the Device Independent source.
  243. You should not have to change any of these routines.
  244.  
  245. .LP
  246. server/include
  247. .RS
  248. .RE
  249. This directory has dozens of includes that are specific to the server.
  250. Many of them are pairs in the form of XXX.h and XXXstr.h,
  251. the former having #defines for the XXX topic, and the latter having
  252. struct definitions.  This naming convention could not be carried out
  253. systematically as SysV allows only 14 character filenames, which truncates
  254. some of the XXXstr.h file names.  The include files in this directory are
  255. only for DIX and DIX/DDX interfaces; individual modules which export
  256. functionality (such as mi) include the interface-definition header files in
  257. their own directories.
  258.  
  259. .LP
  260. server/os
  261. .RS
  262. .RE
  263. This directory has Operating System specific source, mostly in
  264. subdirectories.
  265.  
  266. .LP
  267. server/os/4.2bsd
  268. .RS
  269. .RE
  270. This is source for UNIX 4.2 BSD (Berkeley UNIX) source.
  271. It will also run on 4.3 BSD and ULTRIX.  This code will also
  272. run on several vendors mixed SysV/4BSD systems.  It provides
  273. many routines which are not very OS specific, but which haven't
  274. been moved elsewhere yet for lack of need (i.e. it runs on
  275. every device which is supported by the sample DDX directories).
  276.  
  277. .LP
  278. This software is contributed to the public as a service.
  279. We welcome contributions from other development groups for inclusion on future distributions.
  280.  
  281.  
  282. .NH 2
  283. Areas of Work to be Done
  284. .XS
  285. Areas of Work to be Done
  286. .XE
  287. .LP
  288. Most of the code for the X server is 
  289. on an industry standard 9 track magnetic tape in
  290. UNIX "tar" backup format.
  291. The missing parts that you must supply
  292. for your particular workstation fall into the following three
  293. categories:
  294. .LP
  295. operating system:
  296. .RS
  297. .RE
  298. Your operating system is the first and most obvious source of differences.
  299. If you have a UNIX 4.2 or 4.3 BSD system, this part will be trivial to port.
  300. The further you move away from that, the harder it will be.
  301. For systems that are not UNIX-based, the hardest part 
  302. of the porting process may be the interface to clients.
  303.  
  304. .LP
  305. input:
  306. .RS
  307. .RE
  308. You need to code specific interfaces for your particular pointing device
  309. (mouse or tablet) and keyboard.
  310. These have to be non-blocking; a scheduler must be supplied
  311. that can wait for input events and client requests to arrive.
  312.  
  313. .LP
  314. output:
  315. .RS
  316. .RE
  317. This is potentially the largest section of code you will need to
  318. write.  If you have a memory-mapped frame buffer display, most of the
  319. code has already been written for you (but optimization may be desired).
  320. If you have color and/or a special-purpose graphics
  321. processor that insists upon doing all of the
  322. work itself, you have a substantial task.
  323.  
  324. .NH 2
  325. About DDX, mfb, cfb, and mi
  326. .XS
  327. About DDX, mfb, cfb, and mi
  328. .XE
  329. .LP
  330. The DDX (device dependent X) layer provides a software interface to a
  331. conceptual hardware device.  The imagined device provides primatives for
  332. drawing lines, arcs, text, filling areas, etc.
  333. These primatives may be actually provided in your hardware, or you may have
  334. to build them out of simpler primatives your hardware does provide.
  335. The mi (machine independent) routines provide software simulation of the
  336. conceptual machine built out of very simple primatives such as GetSpans,
  337. SetSpans, FillSpans, PushPixels, etc., which we call the Pixblit routines.
  338.  
  339. The mfb layer is one implementation of the software interface that connects
  340. to monochrome (one bit deep) framebuffers.  The cfb layer is one
  341. implementation that connects to multi-bit framebuffers.  In both cases, some
  342. functionality is provided by writing directly to the framebuffer. Some more
  343. esoteric functionality is achieved by calling the mi routines.  In order to
  344. be able to use the mi routines, they must also implement Pixblit routines.
  345. Both cfb and mfb have been extensively tuned for Release 4 to run as quickly
  346. as portably possible on a wide variety of machines.  Mfb, in particular, has
  347. some Gnu C Compiler "asm" statements which substantially increase
  348. performance of some operations on both Vax and 68020 CPUs.  Cfb, on the
  349. other hand, can be tuned for new architectures by describing some CPU
  350. characteristics in server/include/servermd.h.
  351.  
  352. The mi code should be portable to all systems.
  353. It calls the Pixblit routines to apply the pixels,
  354. all device dependencies are contained in there.
  355.  
  356. Some routines in mi are not used by the mfb or cfb DDX implementations.
  357. They are provided to make it easier for you to get a simple port running
  358. quickly.  Unfortunately, it is not possible to provide a complete DDX
  359. implementation in mi, you need the Pixblit routines which actually know how
  360. the hardware looks.
  361.  
  362. The mi, mfb, and cfb routines were designed for portability over performance.
  363. Therefore, you may want to spend time optimizing them if you choose to use
  364. them.
  365.  
  366. .NH 2
  367. What do I do?
  368. .XS
  369. What do I do?
  370. .XE
  371. .LP
  372. To start, you should get the simplest server running by
  373. modifying as little as possible, probably using mi and maybe using mfb or cfb.
  374. Later, you can carefully optimize it.
  375.  
  376. The first step is to copy the source code off the tar tape onto your machine.
  377. If yours is a UNIX system, this will be easy.
  378. If not, it may be more difficult.
  379.  
  380. Use the UNIX "tar" command to load the tape onto your machine, if appropriate.
  381. If you have a network running, you might be able to get it from
  382. some other machine on the net by using the UNIX "ftp" command
  383. (some non-UNIX systems also support ftp).
  384.  
  385. One way to load the source onto a non-UNIX system is to load it onto
  386. a UNIX system and move it to your system.
  387. If you are porting to a non-UNIX system, we strongly recommend that you have
  388. a UNIX system available in house for purposes such as this and for testing.
  389.  
  390. The next step is to create a subdirectory under the ddx and os directories
  391. as appropriate for your code.  (See the
  392. "Definition of the Porting Layer" document for details on directories.)
  393. Copy files into these directories from sibling directories that seem closest
  394. to what you will need.
  395. For instance, if you are porting to an IBM 3279 display on an IBM 4361
  396. mini, you create the directories ddx/3279 and os/4361 (or os/370
  397. if you thought this would be portable to other 370 architecture machines).
  398. If you were porting to a 3279 display on a UNIX 4.2 system, you would
  399. make a directory ddx/3279 and use the os/4.2BSD directory the way
  400. it is, if you thought it would work.
  401. (If later in the process you found it did not, you would make your own subdirectory.)
  402.  
  403. Start modifying the code.
  404. Begin with the OS code.
  405. There are file i/o routines to work on, and the byte stream to the client
  406. is important.
  407. Get the byte stream working between your own test programs.
  408.  
  409. The second logical step is to get some form of the X server code running.
  410. Make dummy versions of the input routines and graphical output routines so you
  411. can concentrate on getting initialization right without having the system
  412. crash.
  413. Edit Xmd.h according to the instructions in the section "Machine Dependencies" 
  414. later in this document.
  415. Then compile everything.
  416.  
  417. Next, work on the graphical output.
  418. Fill in whatever you need so that a simple client program that just draws some
  419. graphics on the screen works.
  420. For monochrome screens, setting a few
  421. defines and recompiling the mfb files may be all you need.
  422. (See "Porting MFB" in the Details, below.)
  423. For color screens, setting a few
  424. defines and recompiling the cfb files may be all you need.
  425. (See "Porting CFB" in the Details, below.)
  426.  
  427. The xclock program is a good candidate for testing graphical output.
  428. Depending on your networking software, it might be easiest to
  429. have this test client on the same machine as your server.
  430.  
  431. Finally, work on the input.  Fill in code to handle the keyboard and mouse
  432. (or other pointing device).  The cursor that echoes the position of the
  433. pointing device is better implemented in hardware, but mi does provides
  434. support for a primitive software cursor which is very easy to use.  See the
  435. section on cursors below.
  436.  
  437. Next, optimize.
  438.  
  439. You are done!
  440. For more explanation, see the Details section, below.
  441.  
  442. .NH 2
  443. Cost
  444. .XS
  445. Cost
  446. .XE
  447. .LP
  448. We estimate that a basic monochrome or color server will 
  449. take one to two months to develop if done on
  450. a UNIX 4.2 BSD system by an experienced C programmer who knows the hardware
  451. quite well.
  452.  
  453. The more software you have to write, the longer it will take.
  454. If it is a non-4.2 UNIX system, add one to four weeks.
  455. If it is a non-UNIX system, add one to two months.
  456. If your operating system does not have a network, 
  457. that must be taken into consideration.
  458. If you buy someone else's implementation, add one to four months.
  459. If you decide to write it yourself, add six months to two years.
  460.  
  461. If special graphics hardware (a graphics processor, not just unusual
  462. bitplanes) is involved, it will take much longer.
  463. If you want the code optimized for maximum performance, it will take much,
  464. much longer.
  465.  
  466. The more experienced you are, the less time it will take. 
  467. If you are new to C, add some time.
  468. If your programmer is not familiar with your operating system, it will take
  469. longer.
  470. If you are not familiar with windowing systems, it will take longer; if
  471. you're not even familiar with 2-d raster graphics, it will take longer still.
  472. If you've done ports to X before, it will take less time.
  473. If you are really hot, it will take less time.
  474.  
  475.  
  476. Of course, all of these are just guesstimates.
  477.  
  478. The above figures are for one programmer.
  479. Some gains may be achieved through the parallelism of adding programmers.
  480. But, as Fred Brooks puts it, the bearing
  481. of a child takes nine months, no matter how many women are assigned.
  482.  
  483. If you do distribute the work, it would be best to devise a good partition.
  484. For instance, a reasonable partition might be to have one programmer
  485. work on the operating system, network and input code,
  486. have two more working on graphics output, with one of them concentrating on
  487. text graphics.
  488. We recommend no more than a few programmers at one time.
  489.  
  490. At any rate, if you have a product that is robust enough to
  491. be useful, you are probably about half way to making that product a solid,
  492. finished release.
  493.  
  494. .NH 1
  495. Details
  496. .XS
  497. Details
  498. .XE
  499. .LP
  500. .NH 2
  501. Tools
  502. .XS
  503. Tools
  504. .XE
  505. .LP
  506. .NH 3
  507. The C Compiler
  508. .XS
  509. The C Compiler
  510. .XE
  511. .LP
  512. Your C compiler can have a significant effect upon the time it takes you to
  513. finish the project.
  514. Since the original source was developed on a UNIX system, the closer your
  515. compiler approximates the UNIX C (pcc) compiler, the better.
  516. Depending upon your situation, it may be worthwhile to try more than one C
  517. compiler and use the one that works best.
  518. (Programmer time is quite expensive;
  519. software is frequently much less expensive, even if overpriced.)
  520. If, for instance, the DIX code does not compile without modifications, you may
  521. want to look elsewhere.
  522.  
  523. Sometimes we intentionally  call a routine with the wrong number of arguments.
  524. For instance, there is a routine NoopDDA() in dixutils.c that is used 
  525. widely as a procedure that does nothing.
  526. It has zero arguments but is used for situations where routines get passed
  527. different numbers of arguments.
  528. If this causes problems on your machine, you might need to change the code
  529. or get another compiler.
  530.  
  531. If you are using an 8086 architecture, we recommend you use "large" model 
  532. to get the server running, then switch to mixed model for speed and
  533. space efficiency.
  534.  
  535. .NH 3
  536. Make and Makefiles
  537. .XS
  538. Make and Makefiles
  539. .XE
  540. .LP
  541. "Make" is a UNIX program that manages the compilation process.
  542. It reads in a text file named Makefile describing the source files
  543. that need to be compiled and how.
  544. (This file is frequently called the dependencies file because it describes
  545. the chain of dependencies leading to the final product.)
  546. Make then checks the dates of source, intermediate, and object files,
  547. determines the minimum compiles needed to bring a given result
  548. file up to date, and runs each compilation step as a child process.
  549.  
  550. This idea has been imported to a wide variety of operating systems
  551. (frequently still called "make").
  552. On non-multitasking operating systems, the program frequently 
  553. generates just a batch file with the needed compile commands in it and then
  554. executes this batch file as its final operation.
  555. (Beware: few of these non-UNIX versions contain all the features of the
  556. original.)
  557.  
  558. We recommend using Make or whatever useful substitute you have available.
  559. The makefiles for the UNIX system are included with the tar tape, and they
  560. should work on any UNIX system.
  561. this code does not support "near" and "far" pointers.
  562. This may not be necessary or desirable on 386 systems.
  563. They might not work on your system.
  564. To aid you in generating your own makefiles for your own system, we briefly
  565. describe the syntax of makefiles.
  566.  
  567. The dependency relationships look like this:
  568. .nf
  569.  
  570.     fig.o : fig.c fig.h xyz.h
  571.         cc -abc fig.c
  572.  
  573. .fi
  574. This states that the file fig.o (an object) depends upon fig.c and the two .h
  575. files listed.
  576. If fig.o is found to be older than any of the dependencies,
  577. execute the command(s) listed below it to bring it up to date.
  578.  
  579. Most makefiles look much more complicated.
  580. This is primarily due to the use of macros.
  581. When you have a statement of the form:
  582. .nf
  583.  
  584.     COPTS = -abc -x fig -FPa
  585.  
  586. .fi
  587. this means that you can subsequently use "$(COPTS)" as a
  588. text substitution macro elsewhere in the makefile.
  589. .nf
  590.  
  591.     fig.o : fig.c fig.h xyz.h
  592.         cc $(COPTS) fig.c
  593.  
  594. .fi
  595. This is frequently used as shown to hold C compiler options.
  596. It is also used to hold lists of filenames.
  597. .nf
  598.  
  599.     HFILES = fig.h xyz.h
  600.  
  601.     fig.o : fig.c $(HFILES)
  602.         cc $(COPTS) fig.c
  603.  
  604. .fi
  605.  
  606. Another common cause for confusion in makefiles is that there are special $ 
  607. symbols that signify "the dependencies" or "the product" in a command line.
  608. These can be used in powerful constructs that will indicate, in just a few lines,
  609. "compile all .c files that you need to compile and do it this way."
  610.  
  611. Consult UNIX documentation for more details.
  612.  
  613. The makefiles supplied with the sample server are not guaranteed to be 
  614. nearly as portable as the code.
  615. In particular, there are situations where special techniques were used to 
  616. get everything to compile.
  617.  
  618. There are some routines that need to be compiled with #defines 
  619. entered on the command line with the -D flag of the UNIX cc command
  620. instead of with a normal #define directive.
  621. If you don't have such a facility with your compiler, you should put such #defines
  622. in an .h file and do some file copying in the makefile to achieve the same result.
  623.  
  624. .NH 3
  625. Debuggers
  626. .XS
  627. Debuggers
  628. .XE
  629. .LP
  630. Because you are drawing graphics on the display, you will probably want to use
  631. a debugger that does not use the display.
  632. On some systems, a terminal connected to a serial port is the best way to
  633. communicate with the debugger.
  634. On network systems, you may be able to log into your test machine remotely 
  635. and run the debugger and server from there.
  636.  
  637. .NH 3
  638. Profiling Tools
  639. .XS
  640. Profiling Tools
  641. .XE
  642. .LP
  643. After you have an initial implementation running, you may want to improve its
  644. performance.  A profiler is invaluable for this purpose because it tells you
  645. where you are actually consuming CPU cycles.  You can then change code based
  646. upon hard evidence.  On UNIX systems, you might use the prof and gprof
  647. programs.  To really analyze the code, it is very useful to use a
  648. basic-block profiler (like the MIPS pixie system); most of the frame-buffer
  649. graphics primitives are large functions wrapped around multiple small inner
  650. loops which perform the actual rendering.
  651.  
  652. To gain more insight into performance deficits, the X client "x11perf"
  653. (contrib/demos/x11perf), contributed by DEC, offers a wide array of
  654. measurement tools and an easy base to add more to.  It was used extensively
  655. in the development of the current cfb and mfb drivers, along with the
  656. release 4 changes to various data structures and mi algorithms with
  657. frequently astounding revelations.  It is hard to recommend this program too
  658. much.  Each time you sit down to optimize some area of the server, first
  659. develop a test case and integrate it into x11perf; measuring before and after
  660. to discover performance changes.  X11perf is also useful in profiling the
  661. server as it provides a repeatable sequence of graphics requests; set it up
  662. to use a fixed number of iterations.
  663.  
  664. .NH 2
  665. Operating System Details
  666. .XS
  667. Operating System Details
  668. .XE
  669.  
  670. .NH 3
  671. Machine Dependencies
  672. .XS
  673. Machine Dependencies
  674. .XE
  675. .LP
  676. The sample server is written to be portable to a wide variety of architectures,
  677. including CPU chips with different word sizes and different bit and byte ordering.
  678. Before compiling the code, you should set some defines to indicate what kind of
  679. CPU you have.
  680.  
  681. First, edit Xmd.h.
  682. Change the following:
  683.  
  684. INT32, INT16, INT8 should be signed integers of 32, 16 and 8 bytes.  CARD32,
  685. CARD16 and CARD8 should be equivalent unsigned integers.  BITS32, BITS16 and
  686. BYTE should be types that are most convenient for bit-oriented data.  BOOL
  687. is the most convenient boolean value type that fits in 8 bits.  Change them
  688. according to your compiler.  Unfortunately, most of the mfb and cfb code
  689. "knows" that both int and long are 32 bits and will not work on systems where
  690. this is not the case.  The rest of the server is less encumbered, but as the
  691. sample code has never been run on such machines, it is unknown whether it
  692. will work.  It will certainly not work if long != 32 bits or short != 16
  693. bits.
  694.  
  695. IMAGE_BUFSIZE is the size of a buffer of bytes that GetImage will return.
  696. Smaller systems may want to keep this at 1k or less;
  697. larger systems may put it at a few dozen k.
  698.  
  699. IMAGE_BYTE_ORDER indicates the order of bytes in the image.
  700. On VAXen, this is LSBFirst because the least significant byte is on the left, 
  701. and is sent down the pipe first.
  702. On 68000s it is MSBFirst.
  703.  
  704. BITMAP_BIT_ORDER is the equivalent order of bits within a byte.
  705. On VAXen, this is LSBFirst because the least significant bit is most
  706. toward the left on the screen.
  707. On 68000s it is MSBFirst.
  708.  
  709. BITMAP_SCANLINE_UNIT is the biggest piece of memory in which
  710. IMAGE_BYTE_ORDER applies (in bits).  For most hardware, 32 is a good value.
  711. Note that mfb and cfb both assume that addresses ascend across the screen
  712. from left to right and then proceed down the screen.
  713.  
  714. BITMAP_SCANLINE_PAD is the chunk size to which
  715. bitmaps sent over the bytestream should be padded.
  716. In other words, if you had a bitmap that only had one bit in it, 
  717. would you want to send 8 bits, 16 bits or 32 bits?
  718.  
  719. LOG2_BITMAP_PAD must be the log base 2 of BITMAP_SCANLINE_PAD.
  720. If BITMAP_SCANLINE_PAD is 32, this must be 5.
  721.  
  722. LOG2_BYTES_PER_SCANLINE_PAD is the log 
  723. base 2 of (BITMAP_SCANLINE_PAD divided by 8, the number of bits in a byte).
  724. If BITMAP_SCANLINE_PAD is 32, this must be 2.
  725.  
  726. .NH 3
  727. Client Access
  728. .XS
  729. Client Access
  730. .XE
  731. .LP
  732. On many systems, one large section of code to be written may be the client
  733. access.
  734. X requires a reliable byte stream that can handle binary data.
  735. The sample server has code in it to communicate over three different 
  736. byte streams: TCP/IP Ethernet, DECNET, and UNIX domain sockets.
  737.  
  738. If you do not have one of these already, you may find 
  739. the byte stream somewhat time consuming to develop.
  740. If you have an operating system other than a UNIX 4.2 BSD system 
  741. there is more work involved in client access.
  742. If it is another UNIX system, it is somewhat easier.
  743. The less it resembles 4.2 BSD, the more difficult it will be.
  744.  
  745. If you can't use TCP/IP Ethernet, DECNET or UNIX domain sockets,
  746. the alternative is to use some other byte stream mechanism. 
  747. This will also have to be dealt with on the X client side
  748. (there is an implementation-specific routine in the X library
  749. to communicate with the server).
  750. You might start out by implementing both sides in the same 
  751. machine as long as the
  752. client and server are separate processes and there is a convenient interprocess
  753. bytestream mechanism.
  754. In particular, this may be a first step toward implementation of your 
  755. alternate inter-machine client-communication scheme.
  756.  
  757. In theory, any reliable byte stream will work.
  758. Its throughput should be approximately 5k bytes per second or more;
  759. otherwise performance will
  760. deteriorate.
  761.  
  762. For instance, an RS-232 or RS-422 link would work,
  763. although its performance would leave much to be
  764. desired unless you could achieve a baud rate of 56kbaud or greater.
  765. Since 8-bit binary data is regularly transmitted, your bytestream
  766. cannot use command characters for
  767. handshaking and protocol (such as XON/XOFF).
  768. Many modems or other telecommunication
  769. equipment will not work if designed for just normal ASCII communications
  770. because they may intercept certain control characters.
  771. Also, an RS-422 link would only offer one client-server bytestream, 
  772. whereas you may want more than one such connection.
  773.  
  774. .NH 3
  775. Multi-Processor OS's and Graphic Processors
  776. .XS
  777. Multi-Processor OS's and Graphic Processors
  778. .XE
  779. .LP
  780. The X server runs as a single process that imitates multitasking 
  781. using an event-dispatching loop that checks for things to do from all sources
  782. and processes them one at a time.
  783. Many operations do not consume much time, so the multitasking
  784. appearance is upheld; but certain graphics operations may consume
  785. substantial amounts of CPU time.
  786. If another CPU or a graphics processor were
  787. available for these tasks, a significant gain in performance
  788. could be realized.
  789.  
  790. Graphics processors, in particular, can offer a unique opportunity to create
  791. a very high-performance X server.  See the section "Implementing On Top of
  792. Another Graphics System" for more details if you have a graphics processor.
  793.  
  794. The X sample server was written as a single-threaded program for a single processor.
  795. A multi-processor system with a core processor (running the main server
  796. code) might dispatch tasks to a set of slave processors that 
  797. effect low-level graphics operations.
  798. Or it may even have a completely different scheduling system, with multiple 
  799. processors participating in the dispatch loop.
  800. In such cases, large parts of the server code will probably need to be rewritten.
  801. In particular, there are shared resources among clients, 
  802. and you need to ensure that requests received by the server are executed 
  803. in apparent synchrony, and you must ensure that global data structures such as the 
  804. window tree and the resource table are maintained correctly.
  805.  
  806. X is merely a bytestream protocol and anyone can write any software 
  807. to implement it in any language on any computer system.
  808. The sample server is merely one implementation.
  809.  
  810. .NH 3
  811. Server Reset
  812. .XS
  813. Server Reset
  814. .XE
  815. .LP
  816. The X server will reset itself immediately after all clients terminate.
  817. It is helpful to provide a way
  818. for the user to cause the server to terminate all client connections and reset
  819. itself.
  820. At an appropriate time, your server can cause all clients to be terminated by
  821. calling DoomClients().
  822. The following cycle through the dispatch loop, all clients will be terminated
  823. in a somewhat reasonable way.
  824. This will cause a reset.
  825. Upon reset, you should instruct your network to close all open client
  826. connections.
  827.  
  828. For instance, when the server process receives a SIGHUP
  829. signal on UNIX systems, the signal routine calls DoomClients().
  830. On a non-UNIX system, you may prefer a special sequence
  831. of modifiers and keys at the keyboard.
  832. Whatever the user does, all windows and
  833. applications will be closed and the user will have only an empty screen.
  834.  
  835. .NH 3
  836. Shutdown
  837. .XS
  838. Shutdown
  839. .XE
  840. .LP
  841. Depending upon your workstation environment,
  842. you may want your X11 server to run forever, or 
  843. you may want to provide a way for the user to cause the server to quit 
  844. gracefully without turning off the machine.
  845. Your server can quit by calling KillServerResources(), closing all network
  846. connections and then calling exit().
  847.  
  848. For instance, on UNIX systems, when the server process gets a SIGINT or SIGTERM
  849. signal, it calls KillServerResources() and then exit().
  850. On a non-UNIX system, you may prefer to have the user press a special sequence
  851. of modifiers and keys at the keyboard.
  852. Whatever the user does to accomplish this, it will cause the X11 server
  853. to return to your operating system and/or shell.
  854. You may want to clear the graphics screen(s) before exiting.
  855.  
  856. .NH 2
  857. Input Details
  858. .XS
  859. Input Details
  860. .XE
  861. .LP
  862.  
  863. .NH 3
  864. The WaitForSomething Scheduler
  865. .XS
  866. The WaitForSomething Scheduler
  867. .XE
  868. .LP
  869. WaitForSomething() must wait for any of three occurrences: 
  870. a hardware input event is received,
  871. a request from a client is received, or a request from a new client to open a
  872. connection is received.
  873. In the interim, you can do anything you want.
  874. On a multitasking system, you probably want to block yourself.
  875. This can be accomplished using mechanisms such as select(2) on 4.2BSD, or
  876. poll(2) on V.3.  On systems on which the entire machine is dedicated to the X
  877. server you can loop endlessly, checking for input and client requests.
  878.  
  879. It would be unwise to depend exclusively upon
  880. idle times for polling the keyboard and pointing device.
  881. You should also poll these input devices at other times.
  882. In fact, these tasks should be monitored by an interrupt service routine
  883. checking at regular intervals.
  884. Otherwise, the users will be constantly annoyed when their keystrokes and mouse
  885. events are lost.
  886. Also, many paint-style programs depend upon regular
  887. pointing-device event-reporting to enable the user to draw 
  888. smooth curves with the pointing device
  889. without leaps from one cursor location to another.
  890. (Even if the hardware can queue one or two such events, some graphic operations
  891. such as copying a large image can consume more time 
  892. than a few keystrokes in rapid succession
  893. by a touch typist.)
  894.  
  895. DIX will process requests from each client
  896. until the variable isItTimeToYield is set.  
  897. If you do not set it, you will enable one client to lock out all others by constantly
  898. drawing graphics.
  899. Therefore, you should devise a strategy for setting isItTimeToYield
  900. and ending the "timeslice" of a time-consuming client.
  901. The sample server will set this after ten requests have been read from the same
  902. client.
  903.  
  904. The DIX code will service each client in the order received from WaitForSomething().
  905. You might tune the server so that if you write an event to a client, 
  906. the priority of that client increases, by returning him earlier in 
  907. the list or allowing more time
  908. before setting isItTimeToYield.    
  909. You might set isItTimeToYield if the current
  910. request changes the window tree (causing exposures).  
  911.  
  912. .NH 3
  913. Keyboards
  914. .XS
  915. Keyboards
  916. .XE
  917. .LP
  918. The keyboard consists of two kinds of keys, regular keys and modifier keys.
  919. Modifier keys,
  920. like Shift and Control, are keys the user presses while typing regular keys.
  921.  
  922. Your keyboard must be able to indicate when the user presses or releases
  923. keys.
  924. More specifically, your keyboard-interface software must be able to generate
  925. a KeyPress when a modifier or a regular key is pressed
  926. and a KeyRelease when a modifier key is released.
  927. You must also generate a KeyRelease for a normal key,
  928. but you can generate it immediately after the KeyPress is queued.
  929. If you cannot at least do this, you may have problems.
  930.  
  931. If your keyboard currently generates queue events
  932. upon each key motion or calls an
  933. interrupt routine that can do this, your situation is improved.
  934.  
  935. If you have a system in which a keymap
  936. has one bit for each key that is
  937. being pressed, you simply need to check this keymap
  938. at regular intervals in an interrupt service routine and
  939. queue events on an internal queue you maintain.
  940.  
  941. If you have a keyboard at the other end of a serial line, things become more difficult
  942. because you must reverse-map your ASCII characters
  943. into keycodes.
  944. In addition, you need to simulate modifier keys being used.
  945. For instance, when you get a lowercase "a", you must send a KeyPress
  946. for the "A" key, then a KeyRelease for "A".
  947. If you get an uppercase "A", you must send a KeyPress
  948. for the Shift key, send a KeyPress
  949. for the "A" key, then a KeyRelease for "A",
  950. then a KeyRelease for Shift.
  951. If you get a space character, you do not know if the shift key has been pressed,
  952. so you assume it has not.
  953. Between keystrokes, there is no way to know if the shift key has been pressed.
  954. Since with this scheme the client cannot ascertain
  955. when the user is pressing the shift key without typing any keys, 
  956. some client applications that try to detect this will not operate properly.
  957.  
  958. If you want autorepeat, you must simulate this in your code or hardware by 
  959. generating KeyPress and KeyRelease events when appropriate.
  960. The X protocol specification describes in detail how these options are 
  961. set by a client.
  962.  
  963. .NH 3
  964. Pointing Devices
  965. .XS
  966. Pointing Devices
  967. .XE
  968. .LP
  969. The pointing device may be a mouse, a graphics tablet, a light pen,
  970. a touch screen, a trackball, a joystick, a pair of thumbwheels,
  971. or any other device that allows the user to indicate
  972. a location on a two-dimensional surface.
  973. The surface should bear some resemblance to the screen, because a visible
  974. cursor is displayed on the screen at a location that corresponds to the 
  975. pointing-device location.
  976. The pointing device must report a location as a graphics coordinate on the screen.
  977.  
  978. The pointing device must have one or more "buttons" or other momentary control
  979. that the user can touch or press, such that the software driver can report a
  980. "press" and a "release" event.
  981. For instance, a touch screen can report press and release events when the user touches
  982. the screen.
  983. A trackball will probably require one or more separate buttons.
  984.  
  985. Some of these pointing devices are absolute, some are relative.
  986. For instance, with a touch screen, the user directly indicates 
  987. the desired location on the screen.
  988. Mice and trackballs, on the other hand, only provide relative 
  989. motion information; some other hardware or software must integrate
  990. these moves into a location.
  991. A graphics tablet is on the absolute side, but requires a mapping
  992. between the absolute coordinates on the tablet surface
  993. and the screen coordinates.
  994.  
  995. Some relative devices, such as mice, have a scheme in software
  996. or firmware to "accelerate" the motion of the mouse.
  997. For instance, on the Apple Macintosh, the interrupt service routine
  998. for mouse motions checks each increment to be added to the
  999. cursor location.  If the jump is past a certain threshold, 
  1000. it doubles the jump distance.
  1001. In this way, the user can move the mouse quickly across the screen, while
  1002. still retaining fine control over the location for detail work.
  1003. Unfortunately, this technique is frequently used because
  1004. the hardware simply cannot generate fine enough position increments.
  1005. If you implement or have available such a scheme, you should allow standard
  1006. control calls from a client to turn this effect off and on.
  1007.  
  1008. Buttons are numbered starting with one.
  1009. Probably, the left button on a mouse should be number one and
  1010. they should be numbered towards the right from there.
  1011. Client applications that use fewer buttons than you have will start with
  1012. one and use only as many as needed.
  1013. Since the X protocol specifies mechanism, and not policy,
  1014. programs that depend upon more mouse buttons than you have
  1015. may end up waiting for a long time before you 
  1016. hand it a button click which you cannot generate.
  1017. On the other hand, light pens, graphics tablets with pens, and touch screens
  1018. all implicitly have one "button", so it is reasonable to assume
  1019. that client developers will be encouraged to consider one-button pointing devices.
  1020.  
  1021. Keep in mind that the mainstream pointing 
  1022. devices will be mice with one or more
  1023. buttons and graphics tablets.
  1024. Client programs written with one pointing device 
  1025. in mind may prove hard to use with another
  1026. pointing device.
  1027. That is, programs written for a mouse 
  1028. usually assume that the mouse location
  1029. can be chosen very accurately.  If your touch 
  1030. screen is coarse, it may be very frustrating
  1031. to use.
  1032. Also, a touch screen usually cannot generate mouse move
  1033. events while the mouse "button" is not "pressed".
  1034.  
  1035. Make a mouse in a multiple screen environment
  1036. move from one screen to the next by creating the impression that
  1037. the screens are adjacent to one another;
  1038. when the user moves the pointing device off the edge of one screen, 
  1039. the cursor moves onto another.
  1040. X provides no policy for this, and you are free to make any geometric
  1041. models you please.
  1042.  
  1043. .NH 2
  1044. Graphics Output Details
  1045. .XS
  1046. Graphics Output Details
  1047. .XE
  1048. .LP
  1049. .NH 3
  1050. Porting MFB
  1051. .XS
  1052. Porting MFB
  1053. .XE
  1054. .LP
  1055. If your screen is a simple monochrome frame buffer, you probably want to
  1056. start by porting the mi and mfb routines.  These will get you up quickly so
  1057. you have something that works on which to build.  Mfb has been extensively
  1058. tuned for a few environments; in particular mfb runs very well on 68020 and
  1059. vax CPUs where GNU CC is available.  It also runs quite well on many RISC
  1060. processors, where C compiler technology is more able to optimize some of the
  1061. common operations.  Although you could easily expend considerable time
  1062. optimizing it, it is not unreasonable to leave most mfb routines the way
  1063. they are.
  1064.  
  1065. The mfb routines are extremely portable.
  1066. Most monochrome screens need only a half-dozen defines changed
  1067. before the code works.
  1068. System bit and byte order and other machine dependencies 
  1069. are given by #defines.
  1070. (It assumes that byte ordering on the screen is
  1071. the same as byte ordering in main memory.)
  1072.  
  1073. First, make sure you have edited Xmd.h for your CPU.
  1074. See the section "Machine Dependencies" for instructions on how to do this.
  1075. Then edit server/include/servermd.h to set up bit/byte orders and font
  1076. padding information (mfb will work with any font padding, but MSBFirst
  1077. machines work best with GLYPHPADBYTES == 4, GETLEFTBITS_ALIGNMENT == 1).
  1078.  
  1079. Next, write a screen initialization routine which sets the whitePixel and
  1080. blackPixel values in the screen structure and calls mfbScreenInit with
  1081. appropriate parameters; in particular you'll need to pass the address
  1082. of the frame buffer, the screen size in pixels, both horizontal and
  1083. vertical resolution in dots/inch (truncated to an int, which limits the
  1084. accuracy a bit) and the frame buffer width in pixels.  This last parameter
  1085. may seem redundant, but many displays have extra framebuffer memory per
  1086. scanline which is not visible on the display.  Set this final parameter to
  1087. the total pixel width of the display and mfb will ignore the invisible
  1088. space.  You could just type in a literal address in hexadecimal for the
  1089. frame buffer address, but you may want to be a bit more sophisticated.
  1090.  
  1091. In this screen initialization routine, you'll want to initialize the various
  1092. screen functions which apply to your hardware; hardware cursor routines
  1093. (or mi software cursors) should be set up here.  Mfb requires that the
  1094. CloseScreen function which it stores in the screen be called at server reset
  1095. time, make sure you wrap it if you need your own hooks here.  If
  1096. mfbScreenInit returns without troubles (TRUE), call
  1097. mfbCreateDefColormap(pScreen) to initialize the default colormap with
  1098. appropriate values.
  1099.  
  1100. That's it!  All other machine dependencies should be 
  1101. taken care of, for
  1102. most screens.
  1103.  
  1104. If you have an interlaced screen, where rows of neighboring pixels
  1105. are not neighboring in memory, there is a way to make mfb work on it.
  1106. The changes needed are few; carry them out carefully.
  1107. They involve changing the mapping from  the row number to
  1108. address.  Look for places where we multiply by devKind or width.
  1109.  
  1110.  
  1111. .NH 3
  1112. Porting CFB
  1113. .XS
  1114. Porting CFB
  1115. .XE
  1116. .LP
  1117. If your screen is a simple packed-pixel frame buffer (either gray scale or
  1118. color), you will want to start by porting the mi, cfb and mfb routines.
  1119. You'll need to use mfb, even though your screen is color, as each server is
  1120. required to support 1-bit pixmaps.  The cfb routines have been extensively
  1121. tuned for 1-byte-per-pixel displays and will work quite well with little
  1122. change.  On other displays (2 bit up to 32 bit), the existing code will
  1123. still work, but in many areas performance will be disappointing.
  1124.  
  1125. The cfb routines are also extremely portable.  Most color screens need only
  1126. a few changes to Xmd.h and server/include/servermd.h.  The 8-bit specific
  1127. cfb text code works best with GLYPHPADBYTES == 4, GETLEFT_BITS_ALIGNMENT ==
  1128. 1, but will function with any padding.  Also in servermd.h are several
  1129. CPU specific tuning parameters.  Read the comments carefully at the top of
  1130. the file and set the ones appropriate for your CPU.  They do not affect the
  1131. correctness of the code, but can offer substantial performance gains if set
  1132. correctly.  If you are unsure, guess and use a profiling tool to discover
  1133. which set work best.  As with the mfb code, you could spend almost unbounded
  1134. effort tuning various portions of the cfb layer for your particular system;
  1135. but most of the code should run well enough unchanged to not warrant the
  1136. effort.
  1137.  
  1138. Finally, set up an initialization routine which calls cfbScreenInit which
  1139. uses arguments similar to those used by mfbScreenInit, the sizes are all
  1140. still in pixels.  CfbScreenInit does take an additional parameter before the
  1141. framebuffer width, the visual class of the default visual.  Set this
  1142. appropriately (probably PseudoColor).  You needn't set up
  1143. whitePixel/blackPixel on pseudo color machines as cfbCreateDefColormap()
  1144. will pick appropriate values and store them in the colormap when called
  1145. after cfbScreenInit returns success.  If you want to force the values for
  1146. whitePixel/blackPixel, set them in the screen structure after cfbScreenInit
  1147. and before cfbCreateDefColormap.
  1148.  
  1149. .NH 3
  1150. Implementing On Top of Another Graphics System
  1151. .XS
  1152. Implementing On Top of Another Graphics System
  1153. .XE
  1154. .LP
  1155. Many workstations already have their own graphics library or even their own
  1156. windowing system.  In order to coexist with the rest of the world as
  1157. peacefully as possible, you may want to implement your X server on top of
  1158. such a library.  In fact, your machine may come with its own graphics
  1159. processor that can greatly speed up graphics if used judiciously.  Beware,
  1160. however, that many X clients draw small objects, or only a few at a time.
  1161. The overhead for translating X requests into graphics-system primitives may
  1162. dominate the drawing time and cause the resultant server to be slower than a
  1163. simple dumb frame-buffer system.  Do not casually assume that the graphics
  1164. processor is the fastest way to do things.  Profile, profile, profile.
  1165.  
  1166. Since such graphic systems usually perform high level operations such
  1167. as line drawing, text drawing, and area fill,
  1168. you would start accommodating them at the "Drawing Primitives" level.
  1169. In other words, you would rewrite one or more of the
  1170. drawing primitive routines provided (such as miPutImage(),
  1171. miPolyArc(), miPolyFillRectangle(), or miImageText8()).
  1172. Instead of using the equivalent mi routine, you would
  1173. write your own routine to use the graphics system.
  1174.  
  1175. One problem with a graphics processor, which also occurs
  1176. when trying to implement a server atop an outside graphics
  1177. library, is that the definition of certain functions can change in
  1178. subtle ways.
  1179.  
  1180. For instance, a graphics processor may support text drawing only
  1181. by ORing the glyphs into place;
  1182. the X routines require more sophisticated text-drawing capabilities.
  1183. A more difficult case is that in which a graphics processor can draw only fixed-width
  1184. characters or can draw only 8-pixel-wide characters, or can draw characters
  1185. only in its own hardwired font.
  1186.  
  1187. There are several approaches to this problem.
  1188. First, you can recognize the 80 percent of the situations
  1189. that can be executed by your graphics system, using the graphics system
  1190. for those cases, and then executing the remaining 20 percent
  1191. with mi (and possibly even cfb or mfb) code.
  1192. Your GC validate routine can route
  1193. different requests to various 
  1194. routines to do things differently.
  1195. (See the Definition document for more information on the GC validate routine.)
  1196.  
  1197. Secondly, you can supplement the graphics processor's work.
  1198. You can implement each X primative call for with
  1199. more than one call to your graphics system, possibly with
  1200. some auxiliary touch-up.
  1201.  
  1202. Third, request changes in your graphics processor or library.
  1203.  
  1204. By using as many of these approaches as appropriate, you can maximize the
  1205. overall performance and compatibility of your workstation while 
  1206. correctly interpreting the X protocol.
  1207.  
  1208. Example: Your graphics processor applies glyphs only by "ORing" them into
  1209. the image.
  1210. Make the ImageGlyph routine call the graphics processor to 
  1211. draw the character's rectangle in the
  1212. background color, then call the graphics processor to draw the character.
  1213. If using just a solid-fill style in OR mode, 
  1214. you make the PolyGlyph routine call the graphics processor to 
  1215. draw the character.
  1216. You use the slower mi routines for PolyGlyph routine that must effect 
  1217. tiling, stippling, etc.
  1218.  
  1219. Example:
  1220. A graphics processor can draw only fixed-width
  1221. characters.
  1222. In this case, you use the Validate routine to change the primitive
  1223. procedure pointers in the GC depending upon whether your font is
  1224. fixed width or variable width.
  1225. The fixed-width fonts go directly to the graphics processor.
  1226. The variable-width fonts would be drawn in software, probably using
  1227. routines borrowed from the sample server.
  1228. (Depending upon the application, much text on the screen may be fixed width
  1229. in the default font.)
  1230.  
  1231. Example:  The graphics processor cannot clip to an irregular region as the
  1232. entire Drawing Primitive set must do.  Each routine checks the clipping
  1233. region and ascertains whether the entity to be drawn falls entirely within
  1234. the region.  If so, the drawing is executed by the graphics processor.  If
  1235. any part of the entity is clipped, it is handled by the mi, cfb or mfb code.
  1236.  
  1237. Example:
  1238. A graphics processor can draw text only with its own hardwired font.
  1239. You create the font data that would correspond to your hardwired font,
  1240. including the character glyph images.
  1241. You make up a name for this font and make that your default font.
  1242. Once again, you use the Validate routine to change the primitive
  1243. procedure pointers in the GC depending upon whether your font is
  1244. the hardwired font or not.
  1245. The hardwired font goes directly to the graphics processor, as long as 
  1246. you can handle the fill style and clipping.
  1247. Other fill styles or clipping may be handled by using hardware to draw
  1248. into a pixmap and then applying it to the screen.
  1249. Anything else would be drawn in software, probably using
  1250. routines borrowed from the sample server.
  1251.  
  1252. Example:
  1253. In X, lines are drawn with a model borrowed from PostScript
  1254. in which the width of a line is a scalar number
  1255. and ends of lines can either be butt (squarely cut off perpendicular to line)
  1256. round (semicircular end), or projecting (like butt but extending past end of
  1257. line by 1/2 line width).
  1258. Imagine your graphics processor draws lines by smearing
  1259. a rectangle from the source to destination.
  1260. You get to set the height and width of the rectangle, but nothing else.
  1261. You will not be able to use this operation for X wide lines in any but
  1262. the simplest (i.e. horizontal/vertical or zero-width) cases.
  1263.  
  1264. In X there are few requirements placed on zero-width lines.
  1265. (If you get a line width of zero, the intent is that it be "the fastest,
  1266. easiest line," not an invisible line that has no width.)
  1267. Fill-style rules still apply, the width should be approximately 1 pixel.
  1268. The line style (dash style) should still be processed.
  1269. The join style can be ignored because all join 
  1270. styles look the same at this resolution (except that miter joins for acute
  1271. angles can get very long; you can ignore this effect).
  1272. Your algorithm can be anything reasonable, it is desirable
  1273. that you obey the cap style "NotLast" which indicates whether the
  1274. ending pixel should be drawn.  There is also a requirement that
  1275. the lines be identical in the face of clipping; and a suggestion that
  1276. the lines be identical when drawn in the reverse direction.
  1277. Client programs that are picky about the lines they draw can draw width 1
  1278. lines.  Your GC Validate routine can change the line-drawing
  1279. routine pointer in the GC so that zero width lines get drawn by
  1280. the graphics processor and the others are drawn by mi.
  1281.  
  1282. Of course, the facilities of each graphics processor are unique and 
  1283. each has special considerations.
  1284. This is an area that will require meticulous attention to detail on your part.
  1285.  
  1286. .NH 3
  1287. Hardware Tiling and Stipples
  1288. .XS
  1289. Hardware Tiling and Stipples
  1290. .XE
  1291. .LP
  1292. Some hardware has the ability to apply patterns to the graphic surface.
  1293. X makes a distinction between a tile versus
  1294. a stipple.
  1295. A tile is a "full color" pattern, the depth of which matches the target
  1296. drawable.
  1297. A stipple is a binary pattern that writes the foreground color where there are 1-bits 
  1298. areas and (if opaque) the background color on 0-bit areas.
  1299. In addition, X allows a tile or stipple cell to have any size.
  1300.  
  1301. Some graphics processors can apply patterns that are only
  1302. certain cell sizes, such as 8x8 or 16x16.
  1303. Most CPU chips will apply patterns more efficiently  to some frame buffers
  1304. when the pattern
  1305. width is 8, 16 or 32.
  1306. In these cases, you use the GC validate routine to switch between
  1307. fast pattern writing versus slow pattern writing via the mi routines.
  1308. If your pattern size is a factor of your hardware pattern 
  1309. size (such as 2x4), you can simply
  1310. replicate it to fill the hardware rectangle.
  1311. (Many patterns will, in fact, be such sizes, so this will not be wasted effort.
  1312. There is a request, QueryBestSize,
  1313. that a client can execute to ascertain what sizes are optimal.)
  1314.  
  1315. .NH 3
  1316. Graphic Contexts in Hardware
  1317. .XS
  1318. Graphic Contexts in Hardware
  1319. .XE
  1320. .LP
  1321. Many hardware and firmware graphics systems have internal state analogous to
  1322. X's Graphic Contexts.
  1323. Such settings as current line width, current font, and current foreground color
  1324. can be set in hardware for subsequent drawing operations.
  1325. The sample server provides a mechanism for conveniently and efficiently 
  1326. specifying these settings: the GC validate
  1327. procedure, which is called when necessary just before drawing.
  1328.  
  1329. Each drawable (window or pixmap) has a fixed serial number, which is unique
  1330. for that drawable.
  1331. Each GC has a serial number field that reflects the last 
  1332. drawable for which it was validated.
  1333. Before a drawing operation with a drawable and a GC, the two serial numbers
  1334. are compared;
  1335. and, if different, the validate routine(s) are called to validate the GC.
  1336.  
  1337. When a GC is validated for a drawable, its serial number 
  1338. is set to the serial number of the drawable
  1339. so that the next time these two are used together, the validate routines are not called.
  1340. But the GC serial number is changed when some of its fields are changed, forcing
  1341. a validate the next time around (the high bit is changed- it is unused for anything else).
  1342.  
  1343. In other words, by default this validate
  1344. procedure you write is called only when
  1345. the graphic context about to be
  1346. used in a drawing operation has been changed since the
  1347. last validate for this GC and drawable or if the last validate
  1348. for this GC was for another drawable.
  1349.  
  1350. If you have only one hardware GC state, however, the validate routine must be called
  1351. more often, because it must also be called whenever you switch between different
  1352. GC's.
  1353. For instance, under normal conditions,
  1354. if you drew with drawable a and GC A and then drew with drawable b
  1355. and GC B and kept switching between aA and bB without changing the GC's,
  1356. each would no longer need to be
  1357. validated because their serial numbers would match.
  1358.  
  1359. You could ensure that the validate routines are called for each change of
  1360. the GC in use by keeping a static GC pointer variable that points to the
  1361. last GC used.  When a new GC is validated, the serial number of the last GC
  1362. would be changed (change the high bit -- do not change the rest which is
  1363. clipping information).  Once this has been done, set your static GC pointer
  1364. to point to the new GC.  The validate routine will then be called whenever
  1365. the hardware GC information needs to be changed.  Unfortunately, the
  1366. validate routine is probably much more involved than is necessary for this
  1367. process.  Instead, keep a global variable which points at the current GC in
  1368. use and check in each graphics operation that the global GC pointer matches
  1369. the GC passed in.  If not, call a function to reload the hardware state from
  1370. the new GC and change the global pointer to point at the new GC.  DestroyGC
  1371. would then check to ensure the cached GC pointer was invalidated when the GC
  1372. was deleted.
  1373.  
  1374. If you have a sophisticated graphics processor that
  1375. has, for instance, eight "contexts" of graphic parameters among which it
  1376. can switch, you can retain eight static GC pointers
  1377. (in an array).
  1378. Before each graphic operation, set the hardware
  1379. to use the hardware GC it needs.
  1380. (You might want to run benchmarks to ensure you are not spending
  1381. more time switching hardware GC's than necessary.)
  1382.  
  1383. See the Definition document for more details.
  1384.  
  1385. .NH 3
  1386. Implementing X on top of Another Window System
  1387. .XS
  1388. Implementing X on top of Another Window System
  1389. .XE
  1390. .LP
  1391. If you have another windowing system on top of which you want X to run
  1392. there are several procedures in the ScreenRec and WindowRec 
  1393. you can use to execute almost all window operations.
  1394. (Remember, DIX does not interact with your screen 
  1395. directly, so there is considerable leeway in this area.)
  1396.  
  1397. For instance, the window borders are always drawn with PaintWindowBorder()
  1398. and the background with PaintWindowBackground(), which you supply.
  1399. The contents of windows are drawn with the Drawing Primitives, which you supply.
  1400. In addition, DIX calls your routines CreateWindow() and DestroyWindow() when
  1401. it makes and destroys windows.
  1402. Other hooks are provided for mapping and unmapping windows, moving them,
  1403. and changing their attributes.
  1404.  
  1405. See the Definition document section on windows for more details.
  1406.  
  1407. .NH 3
  1408. Color
  1409. .XS
  1410. Color
  1411. .XE
  1412. .LP
  1413. Color requires special considerations.
  1414. You need to decide what class of display you have (see the Definition
  1415. document, the section on Visuals and Depths).
  1416.  
  1417. Next, set up all of the visuals you will support.
  1418. Each depth can have one or more visuals with which it is associated;
  1419. if your screen has several modes, you can list them all.
  1420. As with depths, it may be best to begin with the simplest
  1421. and then add visuals one at a time.
  1422.  
  1423. Cfb has quite a range of support for colormaps.  It has routines
  1424. which emulate any visual type on a pseudo color system, most of which are
  1425. also appropriate for other hardware types.  You'll need to implement
  1426. StoreColors, InstallColormap, UninstallColormap and ListInstalledColormaps;
  1427. all of which are typically quite short.  Place pointers to these routines in
  1428. the screen structure before calling cfbScreenInit.  If you are not using
  1429. cfb, you may want to extract the colormap code anyway; it is not dependent
  1430. on the rest of that directory.
  1431.  
  1432. You might want to construct your server so that
  1433. it appears to support multiple lookup tables simultaneously, so you can have 
  1434. multiple Colormaps installed at the same time.
  1435. For instance, if you had a display that had ten bits per pixel and
  1436. a lookup table of 1024 entries, instead of declaring the obvious, 
  1437. you could declare that you had a display with depth 8
  1438. and four lookup tables.
  1439. The extra two bits in each pixel would determine the lookup table
  1440. to use for that pixel.
  1441. Each time you wrote into windows on this screen, you would need to write
  1442. those extra two bits surreptitiously to indicate the lookup table 
  1443. to use for this pixel.
  1444. When copying pixel data off the screen onto pixmaps, the window would
  1445. be considered eight deep, the extra two bits would be ignored.
  1446. CopyWindow() would have to attend to these extra bits as it changed 
  1447. the colormap allegiance of affected pixels.
  1448.  
  1449. .NH 3
  1450. Multiple Screens
  1451. .XS
  1452. Multiple Screens
  1453. .XE
  1454. .LP
  1455. If you have multiple screens, the implementation is more complicated.
  1456. Each screen may have its own method of managing windows or drawing graphics.
  1457.  
  1458. Each screen may have a different scheme for its frame buffer.
  1459. Each screen manages pixmaps whose format is specific to that screen.
  1460. There are no commands available to the client
  1461. to transfer pixels directly from one screen to 
  1462. another or between pixmaps of different screens.
  1463.  
  1464. Each server must decide what depths and formats of image pixmaps it is
  1465. willing to transfer between the client and server.
  1466. This usually involves some consensus among the screens.  
  1467. A given server must support depth 1, and probably supports all of the depths of
  1468. its screens.
  1469.  
  1470. Fortunately, you need not implement routines to copy pixels between different
  1471. depths.  The only way for the client to copy pixels between drawables
  1472. of different depths is with CopyPlane, which copies one plane from one
  1473. drawable to another.
  1474. The client can copy whatever planes it needs into 1-deep pixmaps
  1475. and can then logically combine these to achieve any desired result.
  1476.  
  1477. Every drawable has a fixed depth.  Every GC has a fixed depth.
  1478. The GC's depth must match the depth of the drawable for drawing, or an error
  1479. results.  Any tile pixmap used with a GC must be the same depth as the GC.
  1480.  
  1481. All screens should have the same byte and bit ordering.
  1482. If they don't, you need to declare the "real" bit and byte ordering
  1483. to follow one of your screens and set the variables in the screenInfo struct
  1484. to it.
  1485. Conversion would happen in GetImage() and PutImage() for each screen.
  1486.  
  1487. .NH 3
  1488. Backing Store and Save-Unders
  1489. .XS
  1490. Backing Store and Save-Unders
  1491. .XE
  1492. .LP
  1493. Backing Store and Save-Unders are schemes in which the server saves
  1494. parts of windows concealed by other windows so that when they
  1495. become exposed again, the server can replace the pixel values quickly instead
  1496. of asking the client to repaint the window.
  1497.  
  1498. Backing Store is a scheme where a window stores away obscured areas 
  1499. of itself when covered by
  1500. other windows.
  1501. Save-Unders is a scheme where a window saves away parts of the
  1502. windows beneath it when it is placed in front.
  1503. The basic idea is the same, but the subtle differences have important implications.
  1504.  
  1505. With Backing Store, a window tracks its own contents.
  1506. When the client draws into a window that is partially obscured,
  1507. the window must intercept these drawing operations and either cause the
  1508. drawing to happen to the saved backing or forget the saved
  1509. backing so that an expose event is generated the next time
  1510. that part is exposed.
  1511.  
  1512. With Save-Unders, this is difficult because the window would need to 
  1513. know which pixels are associated with which windows;
  1514. it would need to intercept all drawing commands to all windows.
  1515. For this reason, Save-Unders is practical only for situations in which 
  1516. either there will be no drawing underneath, or if there is,
  1517. it can be easily intercepted
  1518. in one location in the code.
  1519. (See the section on software cursors for an example of this.)
  1520.  
  1521. Backing store, on the other hand, is more complicated in another way--
  1522. the pieces of backing that need to be stored are often irregular shapes.
  1523. In the case of X, windows are always rectangular, so the backing store can always
  1524. be saved as a set of rectangular pixmaps.
  1525. If this is done, though, drawing into the backing becomes extremely complicated and
  1526. probably slows the system to the extent that your initial
  1527. performance savings are severely diminished.
  1528. If backing is saved as one large pixmap, you waste pixmap memory; you essentially
  1529. retain a duplicate copy of each window in memory in which the only parts that
  1530. are not used are those exposed on the screen.
  1531.  
  1532. Thus, it is usually most practical simply to discard parts of backing
  1533. store that are drawn onto while hidden;
  1534. an expose event will always execute properly.
  1535.  
  1536. The sample implementation of backing store is very device-independent.
  1537. All that is needed to use it is a small vector of device-specific functions,
  1538. only two of which are typically used; SaveAreas and RestoreAreas:
  1539. .nf
  1540.  
  1541.     (*miBSFuncs->SaveAreas) (pixmap, region, x, y);
  1542.         PixmapPtr pixmap;
  1543.         RegionPtr region;
  1544.         int x, y;
  1545.  
  1546.     (*miBSFuncs->RestoreAreas) (pixmap, region, x, y);
  1547.         PixmapPtr pixmap;
  1548.         RegionPtr region;
  1549.         int x, y;
  1550. .fi
  1551. (*SaveAreas) copies the specified region (which is pixmap relative) from the
  1552. screen starting at (x,y) to the pixmap; (*RestoreAreas) copies the specific
  1553. region (which is screen relative) from the pixmap to the screen, starting at
  1554. (x,y).  If you can provide these two functions; call
  1555. miInitializeBackingStore(pScreen, funcs) and the rest will be taken care
  1556. of.  Cfb and mfb already call miInitializeBackingStore.
  1557.  
  1558. DIX provides SaveUnders when DDX provides BackingStore.  This implementation
  1559. is not as optimal as a real save unders implementation would be, but is
  1560. better than nothing in most cases; the mi backing store implementation
  1561. changes its behavior when bits are saved because of save unders instead
  1562. of backing store.
  1563. .NH 3
  1564. Software Cursors
  1565. .XS
  1566. Software Cursors
  1567. .XE
  1568. .LP
  1569. The sample server is designed for a hardware cursor that maintains 
  1570. a separate cursor bit map
  1571. in hardware so that the video electronics mixes the image of the normal display
  1572. and the cursor before being displayed.
  1573. Nevertheless, a software cursor module is provided with hooks which require
  1574. various levels of support.
  1575.  
  1576. The easiest to use level is the DispCur module (server/ddx/mi/midispcur.c).
  1577. This provides software cursors with nearly no device-specific code.  All
  1578. that is required is that you read events from the pointer device and send
  1579. position update events to the mi routines.  Four routines are required, one
  1580. of which is implemented in mi for the truly meek.  The relevant header file
  1581. is "server/ddx/mi/mipointer.h"; this file contains the function vector
  1582. definition and some useful function defines.
  1583. .nf
  1584.  
  1585.     typedef struct {
  1586.             long    (*EventTime)();        /* pScreen */
  1587.             Bool    (*CursorOffScreen)();    /* ppScreen, px, py */
  1588.             void    (*CrossScreen)();    /* pScreen, entering */
  1589.             void    (*QueueEvent)();    /* pxE, pPointer, pScreen */
  1590.     } miPointerCursorFuncRec, *miPointerCursorFuncPtr;
  1591. .fi
  1592. An initialized structure of this type is passed, along with the screen which
  1593. needs cursors to miDCInitialize(pScreen, &pointerCursorFuncs).  (*EventTime)
  1594. is required to return the time of the last event processed (as 32 bits of
  1595. milliseconds).  This allows the mi cursor support to build events and fill
  1596. in the appropriate data.
  1597.  
  1598. (*CursorOffScreen) is called whenever the cursor would be off of the
  1599. current screen if the user motion were tracked exactly.  This routine
  1600. returns FALSE if the cursor should be confined to the screen, TRUE if cursor
  1601. should wander to some other screen.  ppScreen should be smashed to indicate
  1602. the new screen, px and py should indicate the position on that screen; they
  1603. are initialized to be the position of the cursor on the old screen if the
  1604. cursor were not confined or warped (i.e.  (x,y) is not on the screen).
  1605.  
  1606. (*CrossScreen) is called whenever the cursor is moved on/off of the screen.
  1607. entering is TRUE when pScreen is the screen now containing the cursor and
  1608. FALSE when pScreen used to contain the cursor.
  1609.  
  1610. (*QueueEvent) is called in response to WarpPointer protocol requests.  It
  1611. should place the event at the tail of the input queue to be processed in
  1612. series with the other events; this is frequently quite difficult to
  1613. implement, however, and the mi routine, miPointerQueueEvent, simply
  1614. processes the motion event immediately can be used (this may cause occasional
  1615. small protocol violations).
  1616.  
  1617. When your pointer device moves, call
  1618. .nf
  1619.  
  1620.     miPointerDeltaCursor (pScreen, dx, dy, generateEvent)
  1621.         ScreenPtr pScreen;
  1622.         int dx, dy;
  1623.         Bool generateEvent;
  1624. .fi
  1625. with the distance the device has moved and TRUE for generateEvent.  If you
  1626. device reports absolute coordinates instead, use miPointerMoveCursor
  1627. instead (which replaces the delta coordinates with absolute ones).
  1628.  
  1629. To fill in the current pointer position for other event types, use
  1630. miPointerPosition (pScreen, &rootX, &rootY), passing the address of
  1631. the event rootX, rootY fields which will be filled in as appropriate.
  1632.  
  1633. The other two cursor layers can be investigated by looking through the
  1634. miDispCur layer which uses them.  In particular, you may want to
  1635. use miSprite which allows you to provide device-specific cursor
  1636. drawing primitives to speed up cursor rendering.
  1637.  
  1638. .NH 3
  1639. Limited Hardware Cursors
  1640. .XS
  1641. Limited Hardware Cursors
  1642. .XE
  1643. .LP
  1644. Many hardware cursor systems limit the maximum size of the cursor (for
  1645. instance, to 16 pixels square).
  1646. The X specification, however, specifies that a cursor can be any size.
  1647. It is allowable for the server simply to truncate the cursor to an appropriate
  1648. n-by-m rectangle.  This may be the top-left corner, or it may be any n by m
  1649. pixel rectangle that is entirely within the cursor and contains the hotspot;
  1650. the exact choice is implementation dependent.
  1651.  
  1652. .NH 3
  1653. Fonts in Off-Screen Memory
  1654. .XS
  1655. Fonts in Off-Screen Memory
  1656. .XE
  1657. .LP
  1658. Fonts are probably stored on disk on the server when not in use, probably
  1659. in a bitmap format in binary, a form that is ready to go.
  1660. Character drawing consumes much of the CPU, so you should try to 
  1661. ease the burden.
  1662.  
  1663. Of course, you need to read fonts into memory when they are needed.
  1664. Unless you have an extra megabyte of main memory, it is probably 
  1665. best not to retain them in memory forever; users have
  1666. a tendency to build up large font libraries.
  1667.  
  1668. You should have some scheme for loading fonts into memory on demand and
  1669. for purging old fonts when no longer needed.
  1670. Rarely will people use more than a dozen fonts simultaneously.
  1671. (The main exceptions are programs specifically designed to show a sample of each font
  1672. and novice What You See Is What You Get word processor users.)
  1673. You will probably want to record the font least recently used
  1674. and purge it when required.
  1675. Appropriate algorithms can be found in many places, or you can devise your own.
  1676.  
  1677. The binary format in which the fonts are stored (probably snf) has glyphs
  1678. aligned and padded to byte, 16-bit, or 32-bit boundaries.
  1679. You can decide which based upon #defines.
  1680.  
  1681. .NH 3
  1682. Graphic Memory Usage
  1683. .XS
  1684. Graphic Memory Usage
  1685. .XE
  1686. .LP
  1687. Some servers have extremely complex hardware,
  1688. possibly consisting of multiple frame buffers among which the 
  1689. screen can switch, possibly having a graphics processor.
  1690. Sometimes, the graphics processor has its own address space
  1691. that may include memory in addition to the frame buffer that is displayed on
  1692. the screen.
  1693. Sometimes, the graphics processor can also access main memory in your server.
  1694. Sometimes, your main processor can access graphics-processor memory.
  1695. Sometimes, your main processor cannot access the frame buffer.
  1696.  
  1697. For these situations, you should carefully consider what to put in
  1698. graphics memory and what to put in main memory for your
  1699. particular hardware configuration.
  1700. You should consider putting the following in graphics memory:
  1701.  
  1702. .IP \(bu 5
  1703. Anything you must put in graphics memory
  1704. because of the requirements of your graphics processor
  1705. .IP \(bu 5
  1706. Hardware color lookup tables
  1707. .IP \(bu 5
  1708. Hardware GC information
  1709. .IP \(bu 5
  1710. Cursors
  1711. .IP \(bu 5
  1712. Font Glyphs
  1713. .IP \(bu 5
  1714. Pixmaps
  1715. .IP \(bu 5
  1716. Regions
  1717. .IP \(bu 5
  1718. Save-Unders
  1719. .IP \(bu 5
  1720. Backing Store
  1721. .LP
  1722. Use the GC validate routine to move things in and out of graphics memory.
  1723.  
  1724. If your graphics hardware has limited resources, you might want
  1725. to consider drawing into pixmaps that live in main memory, rather
  1726. than special graphics memory.  To do this, you should provide an in-memory
  1727. version of the Spans functions.  When drawing to an in-memory
  1728. pixmap, and swap these Spans functions and the mi output
  1729. code into the GC at ValidateGC time. Then the mi code will draw
  1730. the appropriate things into the bits in memory.  This will probably 
  1731. be slower than using the graphics hardware, but may be
  1732. easier that dealing with memory allocation on the graphics 
  1733. hardware.  
  1734.  
  1735. Furthermore, you might consider drawing into pixmaps in
  1736. main memory if your hardware does not
  1737. draw according to the X11 spec; mixing the two styles of drawing
  1738. may produce odd results.
  1739.  
  1740. After you have implemented the above, and you use your X server,
  1741. reconsider your decisions.
  1742. (It is difficult to know how you will use an X server before you actually do
  1743. so.)
  1744. You may find that you want to change the use of graphics memory.
  1745.  
  1746. .NH 3
  1747. Graphic Output Tuning
  1748. .XS
  1749. Graphic Output Tuning
  1750. .XE
  1751. .LP
  1752. The mi code is designed to be portable by sacrificing 
  1753. a certain amount of performance.
  1754. Once you have got it running and have a large user base,
  1755. it might be appropriate to make it run faster.  Mfb and cfb have already
  1756. been extensively tuned for many platforms; it is unlikely that you could
  1757. increase performance by substantial amounts without resorting to assembly or
  1758. gratuitous code expansion.
  1759.  
  1760. The overall rule in optimizing software is to collect experimental data.
  1761. Do not subjectively judge whether something "feels" faster;
  1762. subjectivity can be easily led astray.
  1763. Do not merely assume where the performance bottlenecks are: use a profiler;
  1764. run benchmarks; use a stopwatch.
  1765.  
  1766. If you do not have a profiler, try running a series of benchmarks.
  1767. For instance, if you think that a major bottleneck is a certain loop
  1768. in ImageGlyph, try commenting out the loop to see what 
  1769. performance gains are effected.
  1770. Run benchmarks before and after, while running a program that will exercise 
  1771. that function.
  1772. This gives you an indication of whether your hunches are right concerning the
  1773. location of the bottlenecks before 
  1774. you devote a great deal of time implementing and debugging a complex algorithm.
  1775.  
  1776. Before you install an optimization, run benchmarks.
  1777. After you install the optimization, run the benchmarks again to check
  1778. performance gains.
  1779. Complicated software that yields no substantial performance gains 
  1780. will simply be a liability later when the software needs to be modified.
  1781.  
  1782. Much optimization effort should be directed toward the operations that are
  1783. executed most frequently.
  1784. Sometimes, you can make a quick routine to handle a special case 
  1785. that occurs frequently and leave the more unusual cases for more general
  1786. software that takes the time to handle all cases.
  1787. For instance, most items that are drawn will be entirely within the clip
  1788. region.
  1789. Most of those that are not will be entirely outside of the clip region.
  1790. Most drawing is executed with a plane mask of all 1s, and with an alu mode of
  1791. Copy.  Most drawing is done with a solid fill style.
  1792. If draw is done with another fill style, the tile or stipple frequently
  1793. has a size that is a byte or word multiple.
  1794. The cfb and mfb routines have already been optimized for some of these 
  1795. special cases.
  1796.  
  1797. In general, start optimizing where you have a better algorithm or know more
  1798. about the hardware than the portable routines.
  1799.  
  1800. .NH 4
  1801. First-Round Optimization
  1802. .XS
  1803. First-Round Optimization
  1804. .XE
  1805. .LP
  1806. The most important things to optimize first are probably
  1807. text drawing, zero-width lines,
  1808. and large area pixel copying and filling.
  1809.  
  1810. Text drawing is best optimized by working on the Glyph routines.
  1811. You may want to rewrite them in assembly language or implement them in
  1812. hardware.
  1813. Since most glyphs are written with solid fill styles and the glyph images
  1814. usually do not lie on a clip-region boundary, you may want to make your speedy
  1815. routine handle just this special case, and handle everything else with mi,
  1816. cfb and
  1817. mfb routines.
  1818.  
  1819. You can even optimize the mfb and cfb glyph routines to your machine without 
  1820. changing much.
  1821. Fonts glyphs are
  1822. padded to byte boundaries for each scanline.
  1823. You can have this padded to 32-bit boundaries, if desired.
  1824. The
  1825. macro getleftbits() in maskbits.h gets glyph bits from glyphs;
  1826. optimize it for your machine. 
  1827. (For instance, take into account
  1828. byte, word and longword boundaries, whether your machine can
  1829. address 16-bit or 32-bit words, and whether this is efficient.)
  1830.  
  1831. Zero-width lines are a good candidate because the rules for drawing them are relaxed.
  1832. You need not worry about many of the details.
  1833. Frequently, hardware or firmware can generate these.
  1834. The most common lines are vertical and horizontal;
  1835. special routines to draw these may be worthwhile.
  1836.  
  1837. CopyArea and CopyWindow optimization will improve window-movement 
  1838. performance.
  1839. Frequently, a machine will have special hardware to perform such graphic operations.
  1840.  
  1841. .NH 4
  1842. Second Round Optimization
  1843. .XS
  1844. Second Round Optimization
  1845. .XE
  1846. .LP
  1847. The next phase of optimization will probably concentrate on painting 
  1848. window backgrounds,
  1849. wide lines, some of the easy-to-perform rectangle operations, and PushPixels().
  1850.  
  1851. Wide lines no longer present much of an opportunity
  1852. to invest a great deal of 
  1853. work into an optimization and 
  1854. receive much benefit from it.
  1855. The mi code now uses integer arithmetic for nearly all of the
  1856. wide line computations and provides nearly-perfect protocol-conforming
  1857. lines.  Experimentation with moving the rendering into cfb or mfb has shown
  1858. that not much performance is to be gained; if you want to try, the polygon
  1859. edge walking code is written using macros which could easily be used directly
  1860. inside the graphics layer.
  1861.  
  1862. The code you want to look at is in miwideline.c and miwideline.h
  1863.  
  1864. Although wide arcs have seen a substantial speedup since the original
  1865. protocol-conformant code was shipped with R3, it would be nice they ran much
  1866. faster.  Unfortunately, the protocol defines an object which is quartic in
  1867. description, the straight line code solution of which involves several
  1868. square roots and a couple cube roots.  If you examine the implementation in
  1869. miarc.c, you'll see a nightmare of complicated floating point arithmetic.
  1870. These routines attempt to come as close as possible to the protocol
  1871. definition for a wide arc, and suffer tremendously in performance because of
  1872. it.  Wide circles, however, do provide a reasonable opportunity for
  1873. optimization.  As the both inner and outer edges of a wide circle are
  1874. circular (unlike elliptical arcs), a fully-integer circle edge walker is
  1875. used to scan-convert them.  Zero width arcs (like lines) are not completely
  1876. specified by the protocol, and so the traditional integer walker is included
  1877. in mfb, cfb and mi.  If you can't use one of those version directly, look in
  1878. the relevant code in ddx/mi/mizerarc.c,mizerarc.h, ddx/mfb/mfbzerarc.c and
  1879. ddx/cfb/cfbzerarc.c.  
  1880.  
  1881. Also included in cfb for R5 are some interesting optimizations for clipping
  1882. points to rectangles and rendering polygons.  Look in ddx/cfb/cfb8line.c and
  1883. ddx/cfb/cfbply1rct.c for these algorithms.  The polygon code could easily be
  1884. ported to mfb, however the zero-width line code is dependent on having
  1885. addressable pixels.
  1886.  
  1887. PushPixels may also be an important routine to optimize.  This is because it
  1888. is used by the software cursor code.  Both mfb and cfb have heavily tuned
  1889. PushPixels routines which work in solid fill/copy mode and provide adequate
  1890. performance for software cursors.
  1891.