summaryrefslogtreecommitdiff
path: root/hw/dmx/doc/dmx.txt
blob: a207511d65e0105cd82f8d9088d1a38c16c1573c (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377
1378
1379
1380
1381
1382
1383
1384
1385
1386
1387
1388
1389
1390
1391
1392
1393
1394
1395
1396
1397
1398
1399
1400
1401
1402
1403
1404
1405
1406
1407
1408
1409
1410
1411
1412
1413
1414
1415
1416
1417
1418
1419
1420
1421
1422
1423
1424
1425
1426
1427
1428
1429
1430
1431
1432
1433
1434
1435
1436
1437
1438
1439
1440
1441
1442
1443
1444
1445
1446
1447
1448
1449
1450
1451
1452
1453
1454
1455
1456
1457
1458
1459
1460
1461
1462
1463
1464
1465
1466
1467
1468
1469
1470
1471
1472
1473
1474
1475
1476
1477
1478
1479
1480
1481
1482
1483
1484
1485
1486
1487
1488
1489
1490
1491
1492
1493
1494
1495
1496
1497
1498
1499
1500
1501
1502
1503
1504
1505
1506
1507
1508
1509
1510
1511
1512
1513
1514
1515
1516
1517
1518
1519
1520
1521
1522
1523
1524
1525
1526
1527
1528
1529
1530
1531
1532
1533
1534
1535
1536
1537
1538
1539
1540
1541
1542
1543
1544
1545
1546
1547
1548
1549
1550
1551
1552
1553
1554
1555
1556
1557
1558
1559
1560
1561
1562
1563
1564
1565
1566
1567
1568
1569
1570
1571
1572
1573
1574
1575
1576
1577
1578
1579
1580
1581
1582
1583
1584
1585
1586
1587
1588
1589
1590
1591
1592
1593
1594
1595
1596
1597
1598
1599
1600
1601
1602
1603
1604
1605
1606
1607
1608
1609
1610
1611
1612
1613
1614
1615
1616
1617
1618
1619
1620
1621
1622
1623
1624
1625
1626
1627
1628
1629
1630
1631
1632
1633
1634
1635
1636
1637
1638
1639
1640
1641
1642
1643
1644
1645
1646
1647
1648
1649
1650
1651
1652
1653
1654
1655
1656
1657
1658
1659
1660
1661
1662
1663
1664
1665
1666
1667
1668
1669
1670
1671
1672
1673
1674
1675
1676
1677
1678
1679
1680
1681
1682
1683
1684
1685
1686
1687
1688
1689
1690
1691
1692
1693
1694
1695
1696
1697
1698
1699
1700
1701
1702
1703
1704
1705
1706
1707
1708
1709
1710
1711
1712
1713
1714
1715
1716
1717
1718
1719
1720
1721
1722
1723
1724
1725
1726
1727
1728
1729
1730
1731
1732
1733
1734
1735
1736
1737
1738
1739
1740
1741
1742
1743
1744
1745
1746
1747
1748
1749
1750
1751
1752
1753
1754
1755
1756
1757
1758
1759
1760
1761
1762
1763
1764
1765
1766
1767
1768
1769
1770
1771
1772
1773
1774
1775
1776
1777
1778
1779
1780
1781
1782
1783
1784
1785
1786
1787
1788
1789
1790
1791
1792
1793
1794
1795
1796
1797
1798
1799
1800
1801
1802
1803
1804
1805
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815
1816
1817
1818
1819
1820
1821
1822
1823
1824
1825
1826
1827
1828
1829
1830
1831
1832
1833
1834
1835
1836
1837
1838
1839
1840
1841
1842
1843
1844
1845
1846
1847
1848
1849
1850
1851
1852
1853
1854
1855
1856
1857
1858
1859
1860
1861
1862
1863
1864
1865
1866
1867
1868
1869
1870
1871
1872
1873
1874
1875
1876
1877
1878
1879
1880
1881
1882
1883
1884
1885
1886
1887
1888
1889
1890
1891
1892
1893
1894
1895
1896
1897
1898
1899
1900
1901
1902
1903
1904
1905
1906
1907
1908
1909
1910
1911
1912
1913
1914
1915
1916
1917
1918
1919
1920
1921
1922
1923
1924
1925
1926
1927
1928
1929
1930
1931
1932
1933
1934
1935
1936
1937
1938
1939
1940
1941
1942
1943
1944
1945
1946
1947
1948
1949
1950
1951
1952
1953
1954
1955
1956
1957
1958
1959
1960
1961
1962
1963
1964
1965
1966
1967
1968
1969
1970
1971
1972
1973
1974
1975
1976
1977
1978
1979
1980
1981
1982
1983
1984
1985
1986
1987
1988
1989
1990
1991
1992
1993
1994
1995
1996
1997
1998
1999
2000
2001
2002
2003
2004
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
2027
2028
2029
2030
2031
2032
2033
2034
2035
2036
2037
2038
2039
2040
2041
2042
2043
2044
2045
2046
2047
2048
2049
2050
2051
2052
2053
2054
2055
2056
2057
2058
2059
2060
2061
2062
2063
2064
2065
2066
2067
2068
2069
2070
2071
2072
2073
2074
2075
2076
2077
2078
2079
2080
2081
2082
2083
2084
2085
2086
2087
2088
2089
2090
2091
2092
2093
2094
2095
2096
2097
2098
2099
2100
2101
2102
2103
2104
2105
2106
2107
2108
2109
2110
2111
2112
2113
2114
2115
2116
2117
2118
2119
2120
2121
2122
2123
2124
2125
2126
2127
2128
2129
2130
2131
2132
2133
2134
2135
2136
2137
2138
2139
2140
2141
2142
2143
2144
2145
2146
2147
2148
2149
2150
2151
2152
2153
2154
2155
2156
2157
2158
2159
2160
2161
2162
2163
2164
2165
2166
2167
2168
2169
2170
2171
2172
2173
2174
2175
2176
2177
2178
2179
2180
2181
2182
2183
2184
2185
2186
2187
2188
2189
2190
2191
2192
2193
2194
2195
2196
2197
2198
2199
2200
2201
2202
2203
2204
2205
2206
2207
2208
2209
2210
2211
2212
2213
2214
2215
2216
2217
2218
2219
2220
2221
2222
2223
2224
2225
2226
2227
2228
2229
2230
2231
2232
2233
2234
2235
2236
2237
2238
2239
2240
2241
2242
2243
2244
2245
2246
2247
2248
2249
2250
2251
2252
2253
2254
2255
2256
2257
2258
2259
2260
2261
2262
2263
2264
2265
2266
2267
2268
2269
2270
2271
2272
2273
2274
2275
2276
2277
2278
2279
2280
2281
2282
2283
2284
2285
2286
2287
2288
2289
2290
2291
2292
2293
2294
2295
2296
2297
2298
2299
2300
2301
2302
2303
2304
2305
2306
2307
2308
2309
2310
2311
2312
2313
2314
2315
2316
2317
2318
2319
2320
2321
2322
2323
2324
2325
2326
2327
2328
2329
2330
2331
2332
2333
2334
2335
2336
2337
2338
2339
2340
2341
2342
2343
2344
2345
2346
2347
2348
2349
2350
2351
2352
2353
2354
2355
2356
2357
2358
2359
2360
2361
2362
2363
2364
2365
2366
2367
2368
2369
2370
2371
2372
2373
2374
2375
2376
2377
2378
2379
2380
2381
2382
2383
2384
2385
2386
2387
2388
2389
2390
2391
2392
2393
2394
2395
2396
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407
2408
2409
2410
2411
2412
2413
2414
2415
2416
2417
2418
2419
2420
2421
2422
2423
2424
2425
2426
2427
2428
2429
2430
2431
2432
2433
2434
2435
2436
2437
2438
2439
2440
2441
2442
2443
2444
2445
2446
2447
2448
2449
2450
2451
2452
2453
2454
2455
2456
2457
2458
2459
2460
2461
2462
2463
2464
2465
2466
2467
2468
2469
2470
2471
2472
2473
2474
2475
2476
2477
2478
2479
2480
2481
2482
2483
2484
2485
2486
2487
2488
2489
2490
2491
2492
2493
2494
2495
2496
2497
2498
2499
2500
2501
2502
2503
2504
2505
2506
2507
2508
2509
2510
2511
2512
2513
2514
2515
2516
2517
2518
2519
2520
2521
2522
2523
2524
2525
2526
2527
2528
2529
2530
2531
2532
2533
2534
2535
2536
2537
2538
2539
2540
2541
2542
2543
2544
2545
2546
2547
2548
2549
2550
2551
2552
2553
2554
2555
2556
2557
2558
2559
2560
2561
2562
2563
2564
2565
2566
2567
2568
2569
2570
2571
2572
2573
2574
2575
2576
2577
2578
2579
2580
2581
2582
2583
2584
2585
2586
2587
2588
2589
2590
2591
2592
2593
Distributed Multihead X design

  Kevin E. Martin

  David H. Dawes

  Rickard E. Faith

   29 June 2004 (created 25 July 2001)

   This document covers the motivation, background, design, and
   implementation of the distributed multihead X (DMX) system. It is a living
   document and describes the current design and implementation details of
   the DMX system. As the project progresses, this document will be
   continually updated to reflect the changes in the code and/or design.
   Copyright 2001 by VA Linux Systems, Inc., Fremont, California. Copyright
   2001-2004 by Red Hat, Inc., Raleigh, North Carolina

     ----------------------------------------------------------------------

   Table of Contents

   Introduction

                The Distributed Multihead X Server

                Layout of Paper

   Development plan

                Bootstrap code

                Input device handling

                Output device handling

                Optimizing DMX

                DMX X extension support

                Common X extension support

                OpenGL support

   Current issues

                Fonts

                Zero width rendering primitives

                Output scaling

                Per-screen colormaps

   A. Appendix

                Background

                             Core input device handling

                             Output handling

                             Xinerama

                Development Results

                             Phase I

                             Phase II

                             Phase III

                             Phase IV

Introduction

  The Distributed Multihead X Server

   Current Open Source multihead solutions are limited to a single physical
   machine. A single X server controls multiple display devices, which can be
   arranged as independent heads or unified into a single desktop (with
   Xinerama). These solutions are limited to the number of physical devices
   that can co-exist in a single machine (e.g., due to the number of AGP/PCI
   slots available for graphics cards). Thus, large tiled displays are not
   currently possible. The work described in this paper will eliminate the
   requirement that the display devices reside in the same physical machine.
   This will be accomplished by developing a front-end proxy X server that
   will control multiple back-end X servers that make up the large display.

   The overall structure of the distributed multihead X (DMX) project is as
   follows: A single front-end X server will act as a proxy to a set of
   back-end X servers, which handle all of the visible rendering. X clients
   will connect to the front-end server just as they normally would to a
   regular X server. The front-end server will present an abstracted view to
   the client of a single large display. This will ensure that all standard X
   clients will continue to operate without modification (limited, as always,
   by the visuals and extensions provided by the X server). Clients that are
   DMX-aware will be able to use an extension to obtain information about the
   back-end servers (e.g., for placement of pop-up windows, window alignments
   by the window manager, etc.).

   The architecture of the DMX server is divided into two main sections:
   input (e.g., mouse and keyboard events) and output (e.g., rendering and
   windowing requests). Each of these are describe briefly below, and the
   rest of this design document will describe them in greater detail.

   The DMX server can receive input from three general types of input
   devices: "local" devices that are physically attached to the machine on
   which DMX is running, "backend" devices that are physically attached to
   one or more of the back-end X servers (and that generate events via the X
   protocol stream from the backend), and "console" devices that can be
   abstracted from any non-back-end X server. Backend and console devices are
   treated differently because the pointer device on the back-end X server
   also controls the location of the hardware X cursor. Full support for
   XInput extension devices is provided.

   Rendering requests will be accepted by the front-end server; however,
   rendering to visible windows will be broken down as needed and sent to the
   appropriate back-end server(s) via X11 library calls for actual rendering.
   The basic framework will follow a Xnest-style approach. GC state will be
   managed in the front-end server and sent to the appropriate back-end
   server(s) as required. Pixmap rendering will (at least initially) be
   handled by the front-end X server. Windowing requests (e.g., ordering,
   mapping, moving, etc.) will handled in the front-end server. If the
   request requires a visible change, the windowing operation will be
   translated into requests for the appropriate back-end server(s). Window
   state will be mirrored in the back-end server(s) as needed.

  Layout of Paper

   The next section describes the general development plan that was actually
   used for implementation. The final section discusses outstanding issues at
   the conclusion of development. The first appendix provides low-level
   technical detail that may be of interest to those intimately familiar with
   the X server architecture. The final appendix describes the four phases of
   development that were performed during the first two years of development.

   The final year of work was divided into 9 tasks that are not described in
   specific sections of this document. The major tasks during that time were
   the enhancement of the reconfiguration ability added in Phase IV, addition
   of support for a dynamic number of back-end displays (instead of a
   hard-coded limit), and the support for back-end display and input removal
   and addition. This work is mentioned in this paper, but is not covered in
   detail.

Development plan

   This section describes the development plan from approximately June 2001
   through July 2003.

  Bootstrap code

   To allow for rapid development of the DMX server by multiple developers
   during the first development stage, the problem will be broken down into
   three tasks: the overall DMX framework, back-end rendering services and
   input device handling services. However, before the work begins on these
   tasks, a simple framework that each developer could use was implemented to
   bootstrap the development effort. This framework renders to a single
   back-end server and provides dummy input devices (i.e., the keyboard and
   mouse). The simple back-end rendering service was implemented using the
   shadow framebuffer support currently available in the XFree86 environment.

   Using this bootstrapping framework, each developer has been able to work
   on each of the tasks listed above independently as follows: the framework
   will be extended to handle arbitrary back-end server configurations; the
   back-end rendering services will be transitioned to the more efficient
   Xnest-style implementation; and, an input device framework to handle
   various input devices via the input extension will be developed.

   Status: The boot strap code is complete.

  Input device handling

   An X server (including the front-end X server) requires two core input
   devices -- a keyboard and a pointer (mouse). These core devices are
   handled and required by the core X11 protocol. Additional types of input
   devices may be attached and utilized via the XInput extension. These are
   usually referred to as ``XInput extension devices'',

   There are some options as to how the front-end X server gets its core
   input devices:

    1. Local Input. The physical input devices (e.g., keyboard and mouse) can
       be attached directly to the front-end X server. In this case, the
       keyboard and mouse on the machine running the front-end X server will
       be used. The front-end will have drivers to read the raw input from
       those devices and convert it into the required X input events (e.g.,
       key press/release, pointer button press/release, pointer motion). The
       front-end keyboard driver will keep track of keyboard properties such
       as key and modifier mappings, autorepeat state, keyboard sound and led
       state. Similarly the front-end pointer driver will keep track if
       pointer properties such as the button mapping and movement
       acceleration parameters. With this option, input is handled fully in
       the front-end X server, and the back-end X servers are used in a
       display-only mode. This option was implemented and works for a limited
       number of Linux-specific devices. Adding additional local input
       devices for other architectures is expected to be relatively simple.

       The following options are available for implementing local input
       devices:

         a. The XFree86 X server has modular input drivers that could be
            adapted for this purpose. The mouse driver supports a wide range
            of mouse types and interfaces, as well as a range of Operating
            System platforms. The keyboard driver in XFree86 is not currently
            as modular as the mouse driver, but could be made so. The XFree86
            X server also has a range of other input drivers for extended
            input devices such as tablets and touch screens. Unfortunately,
            the XFree86 drivers are generally complex, often simultaneously
            providing support for multiple devices across multiple
            architectures; and rely so heavily on XFree86-specific
            helper-functions, that this option was not pursued.

         b. The kdrive X server in XFree86 has built-in drivers that support
            PS/2 mice and keyboard under Linux. The mouse driver can
            indirectly handle other mouse types if the Linux utility gpm is
            used as to translate the native mouse protocol into PS/2 mouse
            format. These drivers could be adapted and built in to the
            front-end X server if this range of hardware and OS support is
            sufficient. While much simpler than the XFree86 drivers, the
            kdrive drivers were not used for the DMX implementation.

         c. Reimplementation of keyboard and mouse drivers from scratch for
            the DMX framework. Because keyboard and mouse drivers are
            relatively trivial to implement, this pathway was selected. Other
            drivers in the X source tree were referenced, and significant
            contributions from other drivers are noted in the DMX source
            code.

    2. Backend Input. The front-end can make use of the core input devices
       attached to one or more of the back-end X servers. Core input events
       from multiple back-ends are merged into a single input event stream.
       This can work sanely when only a single set of input devices is used
       at any given time. The keyboard and pointer state will be handled in
       the front-end, with changes propagated to the back-end servers as
       needed. This option was implemented and works well. Because the core
       pointer on a back-end controls the hardware mouse on that back-end,
       core pointers cannot be treated as XInput extension devices. However,
       all back-end XInput extensions devices can be mapped to either DMX
       core or DMX XInput extension devices.

    3. Console Input. The front-end server could create a console window that
       is displayed on an X server independent of the back-end X servers.
       This console window could display things like the physical screen
       layout, and the front-end could get its core input events from events
       delivered to the console window. This option was implemented and works
       well. To help the human navigate, window outlines are also displayed
       in the console window. Further, console windows can be used as either
       core or XInput extension devices.

    4. Other options were initially explored, but they were all partial
       subsets of the options listed above and, hence, are irrelevant.

   Although extended input devices are not specifically mentioned in the
   Distributed X requirements, the options above were all implemented so that
   XInput extension devices were supported.

   The bootstrap code (Xdmx) had dummy input devices, and these are still
   supported in the final version. These do the necessary initialization to
   satisfy the X server's requirements for core pointer and keyboard devices,
   but no input events are ever generated.

   Status: The input code is complete. Because of the complexity of the
   XFree86 input device drivers (and their heavy reliance on XFree86
   infrastructure), separate low-level device drivers were implemented for
   Xdmx. The following kinds of drivers are supported (in general, the
   devices can be treated arbitrarily as "core" input devices or as XInput
   "extension" devices; and multiple instances of different kinds of devices
   can be simultaneously available):

    1. A "dummy" device drive that never generates events.

    2. "Local" input is from the low-level hardware on which the Xdmx binary
       is running. This is the only area where using the XFree86 driver
       infrastructure would have been helpful, and then only partially, since
       good support for generic USB devices does not yet exist in XFree86 (in
       any case, XFree86 and kdrive driver code was used where possible).
       Currently, the following local devices are supported under Linux
       (porting to other operating systems should be fairly straightforward):

          o Linux keyboard

          o Linux serial mouse (MS)

          o Linux PS/2 mouse

          o USB keyboard

          o USB mouse

          o USB generic device (e.g., joystick, gamepad, etc.)

    3. "Backend" input is taken from one or more of the back-end displays. In
       this case, events are taken from the back-end X server and are
       converted to Xdmx events. Care must be taken so that the sprite moves
       properly on the display from which input is being taken.

    4. "Console" input is taken from an X window that Xdmx creates on the
       operator's display (i.e., on the machine running the Xdmx binary).
       When the operator's mouse is inside the console window, then those
       events are converted to Xdmx events. Several special features are
       available: the console can display outlines of windows that are on the
       Xdmx display (to facilitate navigation), the cursor can be confined to
       the console, and a "fine" mode can be activated to allow very precise
       cursor positioning.

  Output device handling

   The output of the DMX system displays rendering and windowing requests
   across multiple screens. The screens are typically arranged in a grid such
   that together they represent a single large display.

   The output section of the DMX code consists of two parts. The first is in
   the front-end proxy X server (Xdmx), which accepts client connections,
   manages the windows, and potentially renders primitives but does not
   actually display any of the drawing primitives. The second part is the
   back-end X server(s), which accept commands from the front-end server and
   display the results on their screens.

    Initialization

   The DMX front-end must first initialize its screens by connecting to each
   of the back-end X servers and collecting information about each of these
   screens. However, the information collected from the back-end X servers
   might be inconsistent. Handling these cases can be difficult and/or
   inefficient. For example, a two screen system has one back-end X server
   running at 16bpp while the second is running at 32bpp. Converting
   rendering requests (e.g., XPutImage() or XGetImage() requests) to the
   appropriate bit depth can be very time consuming. Analyzing these cases to
   determine how or even if it is possible to handle them is required. The
   current Xinerama code handles many of these cases (e.g., in
   PanoramiXConsolidate()) and will be used as a starting point. In general,
   the best solution is to use homogeneous X servers and display devices.
   Using back-end servers with the same depth is a requirement of the final
   DMX implementation.

   Once this screen consolidation is finished, the relative position of each
   back-end X server's screen in the unified screen is initialized. A
   full-screen window is opened on each of the back-end X servers, and the
   cursor on each screen is turned off. The final DMX implementation can also
   make use of a partial-screen window, or multiple windows per back-end
   screen.

    Handling rendering requests

   After initialization, X applications connect to the front-end server.
   There are two possible implementations of how rendering and windowing
   requests are handled in the DMX system:

    1. A shadow framebuffer is used in the front-end server as the render
       target. In this option, all protocol requests are completely handled
       in the front-end server. All state and resources are maintained in the
       front-end including a shadow copy of the entire framebuffer. The
       framebuffers attached to the back-end servers are updated by
       XPutImage() calls with data taken directly from the shadow
       framebuffer.

       This solution suffers from two main problems. First, it does not take
       advantage of any accelerated hardware available in the system. Second,
       the size of the XPutImage() calls can be quite large and thus will be
       limited by the bandwidth available.

       The initial DMX implementation used a shadow framebuffer by default.

    2. Rendering requests are sent to each back-end server for handling (as
       is done in the Xnest server described above). In this option, certain
       protocol requests are handled in the front-end server and certain
       requests are repackaged and then sent to the back-end servers. The
       framebuffer is distributed across the multiple back-end servers.
       Rendering to the framebuffer is handled on each back-end and can take
       advantage of any acceleration available on the back-end servers'
       graphics display device. State is maintained both in the front and
       back-end servers.

       This solution suffers from two main drawbacks. First, protocol
       requests are sent to all back-end servers -- even those that will
       completely clip the rendering primitive -- which wastes bandwidth and
       processing time. Second, state is maintained both in the front- and
       back-end servers. These drawbacks are not as severe as in option 1
       (above) and can either be overcome through optimizations or are
       acceptable. Therefore, this option will be used in the final
       implementation.

       The final DMX implementation defaults to this mechanism, but also
       supports the shadow framebuffer mechanism. Several optimizations were
       implemented to eliminate the drawbacks of the default mechanism. These
       optimizations are described the section below and in Phase II of the
       Development Results (see appendix).

   Status: Both the shadow framebuffer and Xnest-style code is complete.

  Optimizing DMX

   Initially, the Xnest-style solution's performance will be measured and
   analyzed to determine where the performance bottlenecks exist. There are
   four main areas that will be addressed.

   First, to obtain reasonable interactivity with the first development
   phase, XSync() was called after each protocol request. The XSync()
   function flushes any pending protocol requests. It then waits for the
   back-end to process the request and send a reply that the request has
   completed. This happens with each back-end server and performance greatly
   suffers. As a result of the way XSync() is called in the first development
   phase, the batching that the X11 library performs is effectively defeated.
   The XSync() call usage will be analyzed and optimized by batching calls
   and performing them at regular intervals, except where interactivity will
   suffer (e.g., on cursor movements).

   Second, the initial Xnest-style solution described above sends the
   repackaged protocol requests to all back-end servers regardless of whether
   or not they would be completely clipped out. The requests that are
   trivially rejected on the back-end server wastes the limited bandwidth
   available. By tracking clipping changes in the DMX X server's windowing
   code (e.g., by opening, closing, moving or resizing windows), we can
   determine whether or not back-end windows are visible so that trivial
   tests in the front-end server's GC ops drawing functions can eliminate
   these unnecessary protocol requests.

   Third, each protocol request will be analyzed to determine if it is
   possible to break the request into smaller pieces at display boundaries.
   The initial ones to be analyzed are put and get image requests since they
   will require the greatest bandwidth to transmit data between the front and
   back-end servers. Other protocol requests will be analyzed and those that
   will benefit from breaking them into smaller requests will be implemented.

   Fourth, an extension is being considered that will allow font glyphs to be
   transferred from the front-end DMX X server to each back-end server. This
   extension will permit the front-end to handle all font requests and
   eliminate the requirement that all back-end X servers share the exact same
   fonts as the front-end server. We are investigating the feasibility of
   this extension during this development phase.

   Other potential optimizations will be determined from the performance
   analysis.

   Please note that in our initial design, we proposed optimizing BLT
   operations (e.g., XCopyArea() and window moves) by developing an extension
   that would allow individual back-end servers to directly copy pixel data
   to other back-end servers. This potential optimization was in response to
   the simple image movement implementation that required potentially many
   calls to GetImage() and PutImage(). However, the current Xinerama
   implementation handles these BLT operations differently. Instead of
   copying data to and from screens, they generate expose events -- just as
   happens in the case when a window is moved from off a screen to on screen.
   This approach saves the limited bandwidth available between front and
   back-end servers and is being standardized with Xinerama. It also
   eliminates the potential setup problems and security issues resulting from
   having each back-end server open connections to all other back-end
   servers. Therefore, we suggest accepting Xinerama's expose event solution.

   Also note that the approach proposed in the second and third optimizations
   might cause backing store algorithms in the back-end to be defeated, so a
   DMX X server configuration flag will be added to disable these
   optimizations.

   Status: The optimizations proposed above are complete. It was determined
   that the using the xfs font server was sufficient and creating a new
   mechanism to pass glyphs was redundant; therefore, the fourth optimization
   proposed above was not included in DMX.

  DMX X extension support

   The DMX X server keeps track of all the windowing information on the
   back-end X servers, but does not currently export this information to any
   client applications. An extension will be developed to pass the screen
   information and back-end window IDs to DMX-aware clients. These clients
   can then use this information to directly connect to and render to the
   back-end windows. Bypassing the DMX X server allows DMX-aware clients to
   break up complex rendering requests on their own and send them directly to
   the windows on the back-end server's screens. An example of a client that
   can make effective use of this extension is Chromium.

   Status: The extension, as implemented, is fully documented in
   "Client-to-Server DMX Extension to the X Protocol". Future changes might
   be required based on feedback and other proposed enhancements to DMX.
   Currently, the following facilities are supported:

    1. Screen information (clipping rectangle for each screen relative to the
       virtual screen)

    2. Window information (window IDs and clipping information for each
       back-end window that corresponds to each DMX window)

    3. Input device information (mappings from DMX device IDs to back-end
       device IDs)

    4. Force window creation (so that a client can override the server-side
       lazy window creation optimization)

    5. Reconfiguration (so that a client can request that a screen position
       be changed)

    6. Addition and removal of back-end servers and back-end and console
       inputs.

  Common X extension support

   The XInput, XKeyboard and Shape extensions are commonly used extensions to
   the base X11 protocol. XInput allows multiple and non-standard input
   devices to be accessed simultaneously. These input devices can be
   connected to either the front-end or back-end servers. XKeyboard allows
   much better keyboard mappings control. Shape adds support for arbitrarily
   shaped windows and is used by various window managers. Nearly all
   potential back-end X servers make these extensions available, and support
   for each one will be added to the DMX system.

   In addition to the extensions listed above, support for the X Rendering
   extension (Render) is being developed. Render adds digital image
   composition to the rendering model used by the X Window System. While this
   extension is still under development by Keith Packard of HP, support for
   the current version will be added to the DMX system.

   Support for the XTest extension was added during the first development
   phase.

   Status: The following extensions are supported and are discussed in more
   detail in Phase IV of the Development Results (see appendix):
   BIG-REQUESTS, DEC-XTRAP, DMX, DPMS, Extended-Visual-Information, GLX, LBX,
   RECORD, RENDER, SECURITY, SHAPE, SYNC, X-Resource, XC-APPGROUP, XC-MISC,
   XFree86-Bigfont, XINERAMA, XInputExtension, XKEYBOARD, and XTEST.

  OpenGL support

   OpenGL support using the Mesa code base exists in XFree86 release 4 and
   later. Currently, the direct rendering infrastructure (DRI) provides
   accelerated OpenGL support for local clients and unaccelerated OpenGL
   support (i.e., software rendering) is provided for non-local clients.

   The single head OpenGL support in XFree86 4.x will be extended to use the
   DMX system. When the front and back-end servers are on the same physical
   hardware, it is possible to use the DRI to directly render to the back-end
   servers. First, the existing DRI will be extended to support multiple
   display heads, and then to support the DMX system. OpenGL rendering
   requests will be direct rendering to each back-end X server. The DRI will
   request the screen layout (either from the existing Xinerama extension or
   a DMX-specific extension). Support for synchronized swap buffers will also
   be added (on hardware that supports it). Note that a single front-end
   server with a single back-end server on the same physical machine can
   emulate accelerated indirect rendering.

   When the front and back-end servers are on different physical hardware or
   are using non-XFree86 4.x X servers, a mechanism to render primitives
   across the back-end servers will be provided. There are several options as
   to how this can be implemented.

    1. The existing OpenGL support in each back-end server can be used by
       repackaging rendering primitives and sending them to each back-end
       server. This option is similar to the unoptimized Xnest-style approach
       mentioned above. Optimization of this solution is beyond the scope of
       this project and is better suited to other distributed rendering
       systems.

    2. Rendering to a pixmap in the front-end server using the current
       XFree86 4.x code, and then displaying to the back-ends via calls to
       XPutImage() is another option. This option is similar to the shadow
       frame buffer approach mentioned above. It is slower and bandwidth
       intensive, but has the advantage that the back-end servers are not
       required to have OpenGL support.

   These, and other, options will be investigated in this phase of the work.

   Work by others have made Chromium DMX-aware. Chromium will use the DMX X
   protocol extension to obtain information about the back-end servers and
   will render directly to those servers, bypassing DMX.

   Status: OpenGL support by the glxProxy extension was implemented by SGI
   and has been integrated into the DMX code base.

Current issues

   In this sections the current issues are outlined that require further
   investigation.

  Fonts

   The font path and glyphs need to be the same for the front-end and each of
   the back-end servers. Font glyphs could be sent to the back-end servers as
   necessary but this would consume a significant amount of available
   bandwidth during font rendering for clients that use many different fonts
   (e.g., Netscape). Initially, the font server (xfs) will be used to provide
   the fonts to both the front-end and back-end servers. Other possibilities
   will be investigated during development.

  Zero width rendering primitives

   To allow pixmap and on-screen rendering to be pixel perfect, all back-end
   servers must render zero width primitives exactly the same as the
   front-end renders the primitives to pixmaps. For those back-end servers
   that do not exactly match, zero width primitives will be automatically
   converted to one width primitives. This can be handled in the front-end
   server via the GC state.

  Output scaling

   With very large tiled displays, it might be difficult to read the
   information on the standard X desktop. In particular, the cursor can be
   easily lost and fonts could be difficult to read. Automatic primitive
   scaling might prove to be very useful. We will investigate the possibility
   of scaling the cursor and providing a set of alternate pre-scaled fonts to
   replace the standard fonts that many applications use (e.g., fixed). Other
   options for automatic scaling will also be investigated.

  Per-screen colormaps

   Each screen's default colormap in the set of back-end X servers should be
   able to be adjusted via a configuration utility. This support is would
   allow the back-end screens to be calibrated via custom gamma tables. On
   24-bit systems that support a DirectColor visual, this type of correction
   can be accommodated. One possible implementation would be to advertise to
   X client of the DMX server a TrueColor visual while using DirectColor
   visuals on the back-end servers to implement this type of color
   correction. Other options will be investigated.

A. Appendix

Background

   This section describes the existing Open Source architectures that can be
   used to handle multiple screens and upon which this development project is
   based. This section was written before the implementation was finished,
   and may not reflect actual details of the implementation. It is left for
   historical interest only.

  Core input device handling

   The following is a description of how core input devices are handled by an
   X server.

    InitInput()

   InitInput() is a DDX function that is called at the start of each server
   generation from the X server's main() function. Its purpose is to
   determine what input devices are connected to the X server, register them
   with the DIX and MI layers, and initialize the input event queue.
   InitInput() does not have a return value, but the X server will abort if
   either a core keyboard device or a core pointer device are not registered.
   Extended input (XInput) devices can also be registered in InitInput().

   InitInput() usually has implementation specific code to determine which
   input devices are available. For each input device it will be using, it
   calls AddInputDevice():

   AddInputDevice() This DIX function allocates the device structure,         
                    registers a callback function (which handles device init, 
                    close, on and off), and returns the input handle, which   
                    can be treated as opaque. It is called once for each      
                    input device.                                             

   Once input handles for core keyboard and core pointer devices have been
   obtained from AddInputDevice(). If both core devices are not registered,
   then the X server will exit with a fatal error when it attempts to start
   the input devices in InitAndStartDevices(), which is called directly after
   InitInput() (see below).

   The core pointer device is then registered with the miPointer code (which
   does the high level cursor handling). While this registration is not
   necessary for correct miPointer operation in the current XFree86 code, it
   is still done mostly for compatibility reasons.

   miRegisterPointerDevice() This MI function registers the core pointer's    
                             input handle with with the miPointer code.       

   The final part of InitInput() is the initialization of the input event
   queue handling. In most cases, the event queue handling provided in the MI
   layer is used. The primary XFree86 X server uses its own event queue
   handling to support some special cases related to the XInput extension and
   the XFree86-specific DGA extension. For our purposes, the MI event queue
   handling should be suitable. It is initialized by calling mieqInit():

   mieqInit() This MI function initializes the MI event queue for the core    
              devices, and is passed the public component of the input        
              handles for the two core devices.                               

   If a wakeup handler is required to deliver synchronous input events, it
   can be registered here by calling the DIX function
   RegisterBlockAndWakeupHandlers(). (See the devReadInput() description
   below.)

    InitAndStartDevices()

   InitAndStartDevices() is a DIX function that is called immediately after
   InitInput() from the X server's main() function. Its purpose is to
   initialize each input device that was registered with AddInputDevice(),
   enable each input device that was successfully initialized, and create the
   list of enabled input devices. Once each registered device is processed in
   this way, the list of enabled input devices is checked to make sure that
   both a core keyboard device and core pointer device were registered and
   successfully enabled. If not, InitAndStartDevices() returns failure, and
   results in the the X server exiting with a fatal error.

   Each registered device is initialized by calling its callback
   (dev->deviceProc) with the DEVICE_INIT argument:

   (*dev->deviceProc)(dev, This function initializes the device structs with  
   DEVICE_INIT)            core information relevant to the device.           
                                                                              
                           For pointer devices, this means specifying the     
                           number of buttons, default button mapping, the     
                           function used to get motion events (usually        
                           miPointerGetMotionEvents()), the function used to  
                           change/control the core pointer motion parameters  
                           (acceleration and threshold), and the motion       
                           buffer size.                                       
                                                                              
                           For keyboard devices, this means specifying the    
                           keycode range, default keycode to keysym mapping,  
                           default modifier mapping, and the functions used   
                           to sound the keyboard bell and modify/control the  
                           keyboard parameters (LEDs, bell pitch and          
                           duration, key click, which keys are                
                           auto-repeating, etc).                              

   Each initialized device is enabled by calling EnableDevice():

   EnableDevice() EnableDevice() calls the device callback with DEVICE_ON:    
                                                                              
                  (*dev->deviceProc)(dev, This typically opens and            
                  DEVICE_ON)              initializes the relevant physical   
                                          device, and when appropriate,       
                                          registers the device's file         
                                          descriptor (or equivalent) as a     
                                          valid input source.                 
                                                                              
                  EnableDevice() then adds the device handle to the X         
                  server's global list of enabled devices.                    

   InitAndStartDevices() then verifies that a valid core keyboard and pointer
   has been initialized and enabled. It returns failure if either are
   missing.

    devReadInput()

   Each device will have some function that gets called to read its physical
   input. These may be called in a number of different ways. In the case of
   synchronous I/O, they will be called from a DDX wakeup-handler that gets
   called after the server detects that new input is available. In the case
   of asynchronous I/O, they will be called from a (SIGIO) signal handler
   triggered when new input is available. This function should do at least
   two things: make sure that input events get enqueued, and make sure that
   the cursor gets moved for motion events (except if these are handled later
   by the driver's own event queue processing function, which cannot be done
   when using the MI event queue handling).

   Events are queued by calling mieqEnqueue():

   mieqEnqueue() This MI function is used to add input events to the event    
                 queue. It is simply passed the event to be queued.           

   The cursor position should be updated when motion events are enqueued, by
   calling either miPointerAbsoluteCursor() or miPointerDeltaCursor():

   miPointerAbsoluteCursor() This MI function is used to move the cursor to   
                             the absolute coordinates provided.               
   miPointerDeltaCursor()    This MI function is used to move the cursor      
                             relative to its current position.                

    ProcessInputEvents()

   ProcessInputEvents() is a DDX function that is called from the X server's
   main dispatch loop when new events are available in the input event queue.
   It typically processes the enqueued events, and updates the cursor/pointer
   position. It may also do other DDX-specific event processing.

   Enqueued events are processed by mieqProcessInputEvents() and passed to
   the DIX layer for transmission to clients:

   mieqProcessInputEvents() This function processes each event in the event   
                            queue, and passes it to the device's input        
                            processing function. The DIX layer provides       
                            default functions to do this processing, and they 
                            handle the task of getting the events passed back 
                            to the relevant clients.                          
   miPointerUpdate()        This function resynchronized the cursor position  
                            with the new pointer position. It also takes care 
                            of moving the cursor between screens when needed  
                            in multi-head configurations.                     

    DisableDevice()

   DisableDevice is a DIX function that removes an input device from the list
   of enabled devices. The result of this is that the device no longer
   generates input events. The device's data structures are kept in place,
   and disabling a device like this can be reversed by calling
   EnableDevice(). DisableDevice() may be called from the DDX when it is
   desirable to do so (e.g., the XFree86 server does this when VT switching).
   Except for special cases, this is not normally called for core input
   devices.

   DisableDevice() calls the device's callback function with DEVICE_OFF:

   (*dev->deviceProc)(dev, DEVICE_OFF) This typically closes the relevant     
                                       physical device, and when appropriate, 
                                       unregisters the device's file          
                                       descriptor (or equivalent) as a valid  
                                       input source.                          

   DisableDevice() then removes the device handle from the X server's global
   list of enabled devices.

    CloseDevice()

   CloseDevice is a DIX function that removes an input device from the list
   of available devices. It disables input from the device and frees all data
   structures associated with the device. This function is usually called
   from CloseDownDevices(), which is called from main() at the end of each
   server generation to close all input devices.

   CloseDevice() calls the device's callback function with DEVICE_CLOSE:

   (*dev->deviceProc)(dev, This typically closes the relevant physical        
   DEVICE_CLOSE)           device, and when appropriate, unregisters the      
                           device's file descriptor (or equivalent) as a      
                           valid input source. If any device specific data    
                           structures were allocated when the device was      
                           initialized, they are freed here.                  

   CloseDevice() then frees the data structures that were allocated for the
   device when it was registered/initialized.

    LegalModifier()

   LegalModifier() is a required DDX function that can be used to restrict
   which keys may be modifier keys. This seems to be present for historical
   reasons, so this function should simply return TRUE unconditionally.

  Output handling

   The following sections describe the main functions required to initialize,
   use and close the output device(s) for each screen in the X server.

    InitOutput()

   This DDX function is called near the start of each server generation from
   the X server's main() function. InitOutput()'s main purpose is to
   initialize each screen and fill in the global screenInfo structure for
   each screen. It is passed three arguments: a pointer to the screenInfo
   struct, which it is to initialize, and argc and argv from main(), which
   can be used to determine additional configuration information.

   The primary tasks for this function are outlined below:

    1. Parse configuration info: The first task of InitOutput() is to parses
       any configuration information from the configuration file. In addition
       to the XF86Config file, other configuration information can be taken
       from the command line. The command line options can be gathered either
       in InitOutput() or earlier in the ddxProcessArgument() function, which
       is called by ProcessCommandLine(). The configuration information
       determines the characteristics of the screen(s). For example, in the
       XFree86 X server, the XF86Config file specifies the monitor
       information, the screen resolution, the graphics devices and slots in
       which they are located, and, for Xinerama, the screens' layout.

    2. Initialize screen info: The next task is to initialize the
       screen-dependent internal data structures. For example, part of what
       the XFree86 X server does is to allocate its screen and pixmap private
       indices, probe for graphics devices, compare the probed devices to the
       ones listed in the XF86Config file, and add the ones that match to the
       internal xf86Screens[] structure.

    3. Set pixmap formats: The next task is to initialize the screenInfo's
       image byte order, bitmap bit order and bitmap scanline unit/pad. The
       screenInfo's pixmap format's depth, bits per pixel and scanline
       padding is also initialized at this stage.

    4. Unify screen info: An optional task that might be done at this stage
       is to compare all of the information from the various screens and
       determines if they are compatible (i.e., if the set of screens can be
       unified into a single desktop). This task has potential to be useful
       to the DMX front-end server, if Xinerama's PanoramiXConsolidate()
       function is not sufficient.

   Once these tasks are complete, the valid screens are known and each of
   these screens can be initialized by calling AddScreen().

    AddScreen()

   This DIX function is called from InitOutput(), in the DDX layer, to add
   each new screen to the screenInfo structure. The DDX screen initialization
   function and command line arguments (i.e., argc and argv) are passed to it
   as arguments.

   This function first allocates a new Screen structure and any privates that
   are required. It then initializes some of the fields in the Screen struct
   and sets up the pixmap padding information. Finally, it calls the DDX
   screen initialization function ScreenInit(), which is described below. It
   returns the number of the screen that were just added, or -1 if there is
   insufficient memory to add the screen or if the DDX screen initialization
   fails.

    ScreenInit()

   This DDX function initializes the rest of the Screen structure with either
   generic or screen-specific functions (as necessary). It also fills in
   various screen attributes (e.g., width and height in millimeters, black
   and white pixel values).

   The screen init function usually calls several functions to perform
   certain screen initialization functions. They are described below:

   {mi,*fb}ScreenInit()       The DDX layer's ScreenInit() function usually   
                              calls another layer's ScreenInit() function     
                              (e.g., miScreenInit() or fbScreenInit()) to     
                              initialize the fallbacks that the DDX driver    
                              does not specifically handle.                   
                                                                              
                              After calling another layer's ScreenInit()      
                              function, any screen-specific functions either  
                              wrap or replace the other layer's function      
                              pointers. If a function is to be wrapped, each  
                              of the old function pointers from the other     
                              layer are stored in a screen private area.      
                              Common functions to wrap are CloseScreen() and  
                              SaveScreen().                                   
   miInitializeBackingStore() This MI function initializes the screen's       
                              backing storage functions, which are used to    
                              save areas of windows that are currently        
                              covered by other windows.                       
   miDCInitialize()           This MI function initializes the MI cursor      
                              display structures and function pointers. If a  
                              hardware cursor is used, the DDX layer's        
                              ScreenInit() function will wrap additional      
                              screen and the MI cursor display function       
                              pointers.                                       

   Another common task for ScreenInit() function is to initialize the output
   device state. For example, in the XFree86 X server, the ScreenInit()
   function saves the original state of the video card and then initializes
   the video mode of the graphics device.

    CloseScreen()

   This function restores any wrapped screen functions (and in particular the
   wrapped CloseScreen() function) and restores the state of the output
   device to its original state. It should also free any private data it
   created during the screen initialization.

    GC operations

   When the X server is requested to render drawing primitives, it does so by
   calling drawing functions through the graphics context's operation
   function pointer table (i.e., the GCOps functions). These functions render
   the basic graphics operations such as drawing rectangles, lines, text or
   copying pixmaps. Default routines are provided either by the MI layer,
   which draws indirectly through a simple span interface, or by the
   framebuffer layers (e.g., CFB, MFB, FB), which draw directly to a linearly
   mapped frame buffer.

   To take advantage of special hardware on the graphics device, specific
   GCOps functions can be replaced by device specific code. However, many
   times the graphics devices can handle only a subset of the possible states
   of the GC, so during graphics context validation, appropriate routines are
   selected based on the state and capabilities of the hardware. For example,
   some graphics hardware can accelerate single pixel width lines with
   certain dash patterns. Thus, for dash patterns that are not supported by
   hardware or for width 2 or greater lines, the default routine is chosen
   during GC validation.

   Note that some pointers to functions that draw to the screen are stored in
   the Screen structure. They include GetImage(), GetSpans(), CopyWindow()
   and RestoreAreas().

    Xnest

   The Xnest X server is a special proxy X server that relays the X protocol
   requests that it receives to a ``real'' X server that then processes the
   requests and displays the results, if applicable. To the X applications,
   Xnest appears as if it is a regular X server. However, Xnest is both
   server to the X application and client of the real X server, which will
   actually handle the requests.

   The Xnest server implements all of the standard input and output
   initialization steps outlined above.

   InitOutput()  Xnest takes its configuration information from command line  
                 arguments via ddxProcessArguments(). This information        
                 includes the real X server display to connect to, its        
                 default visual class, the screen depth, the Xnest window's   
                 geometry, etc. Xnest then connects to the real X server and  
                 gathers visual, colormap, depth and pixmap information about 
                 that server's display, creates a window on that server,      
                 which will be used as the root window for Xnest.             
                                                                              
                 Next, Xnest initializes its internal data structures and     
                 uses the data from the real X server's pixmaps to initialize 
                 its own pixmap formats. Finally, it calls                    
                 AddScreen(xnestOpenScreen, argc, argv) to initialize each of 
                 its screens.                                                 
   ScreenInit()  Xnest's ScreenInit() function is called xnestOpenScreen().   
                 This function initializes its screen's depth and visual      
                 information, and then calls miScreenInit() to set up the     
                 default screen functions. It then calls                      
                 miInitializeBackingStore() and miDCInitialize() to           
                 initialize backing store and the software cursor. Finally,   
                 it replaces many of the screen functions with its own        
                 functions that repackage and send the requests to the real X 
                 server to which Xnest is attached.                           
   CloseScreen() This function frees its internal data structure allocations. 
                 Since it replaces instead of wrapping screen functions,      
                 there are no function pointers to unwrap. This can           
                 potentially lead to problems during server regeneration.     
   GC operations The GC operations in Xnest are very simple since they leave  
                 all of the drawing to the real X server to which Xnest is    
                 attached. Each of the GCOps takes the request and sends it   
                 to the real X server using standard Xlib calls. For example, 
                 the X application issues a XDrawLines() call. This function  
                 turns into a protocol request to Xnest, which calls the      
                 xnestPolylines() function through Xnest's GCOps function     
                 pointer table. The xnestPolylines() function is only a       
                 single line, which calls XDrawLines() using the same         
                 arguments that were passed into it. Other GCOps functions    
                 are very similar. Two exceptions to the simple GCOps         
                 functions described above are the image functions and the    
                 BLT operations.                                              
                                                                              
                 The image functions, GetImage() and PutImage(), must use a   
                 temporary image to hold the image to be put of the image     
                 that was just grabbed from the screen while it is in transit 
                 to the real X server or the client. When the image has been  
                 transmitted, the temporary image is destroyed.               
                                                                              
                 The BLT operations, CopyArea() and CopyPlane(), handle not   
                 only the copy function, which is the same as the simple      
                 cases described above, but also the graphics exposures that  
                 result when the GC's graphics exposure bit is set to True.   
                 Graphics exposures are handled in a helper function,         
                 xnestBitBlitHelper(). This function collects the exposure    
                 events from the real X server and, if any resulting in       
                 regions being exposed, then those regions are passed back to 
                 the MI layer so that it can generate exposure events for the 
                 X application.                                               

   The Xnest server takes its input from the X server to which it is
   connected. When the mouse is in the Xnest server's window, keyboard and
   mouse events are received by the Xnest server, repackaged and sent back to
   any client that requests those events.

    Shadow framebuffer

   The most common type of framebuffer is a linear array memory that maps to
   the video memory on the graphics device. However, accessing that video
   memory over an I/O bus (e.g., ISA or PCI) can be slow. The shadow
   framebuffer layer allows the developer to keep the entire framebuffer in
   main memory and copy it back to video memory at regular intervals. It also
   has been extended to handle planar video memory and rotated framebuffers.

   There are two main entry points to the shadow framebuffer code:

   shadowAlloc(width, height, This function allocates the in memory copy of   
   bpp)                       the framebuffer of size width*height*bpp. It    
                              returns a pointer to that memory, which will be 
                              used by the framebuffer ScreenInit() code       
                              during the screen's initialization.             
   shadowInit(pScreen,        This function initializes the shadow            
   updateProc, windowProc)    framebuffer layer. It wraps several screen      
                              drawing functions, and registers a block        
                              handler that will update the screen. The        
                              updateProc is a function that will copy the     
                              damaged regions to the screen, and the          
                              windowProc is a function that is used when the  
                              entire linear video memory range cannot be      
                              accessed simultaneously so that only a window   
                              into that memory is available (e.g., when using 
                              the VGA aperture).                              

   The shadow framebuffer code keeps track of the damaged area of each screen
   by calculating the bounding box of all drawing operations that have
   occurred since the last screen update. Then, when the block handler is
   next called, only the damaged portion of the screen is updated.

   Note that since the shadow framebuffer is kept in main memory, all drawing
   operations are performed by the CPU and, thus, no accelerated hardware
   drawing operations are possible.

  Xinerama

   Xinerama is an X extension that allows multiple physical screens
   controlled by a single X server to appear as a single screen. Although the
   extension allows clients to find the physical screen layout via extension
   requests, it is completely transparent to clients at the core X11 protocol
   level. The original public implementation of Xinerama came from
   Digital/Compaq. XFree86 rewrote it, filling in some missing pieces and
   improving both X11 core protocol compliance and performance. The Xinerama
   extension will be passing through X.Org's standardization process in the
   near future, and the sample implementation will be based on this rewritten
   version.

   The current implementation of Xinerama is based primarily in the DIX
   (device independent) and MI (machine independent) layers of the X server.
   With few exceptions the DDX layers do not need any changes to support
   Xinerama. X server extensions often do need modifications to provide full
   Xinerama functionality.

   The following is a code-level description of how Xinerama functions.

   Note: Because the Xinerama extension was originally called the PanoramiX
   extension, many of the Xinerama functions still have the PanoramiX prefix.

   PanoramiXExtensionInit()         PanoramiXExtensionInit() is a             
                                    device-independent extension function     
                                    that is called at the start of each       
                                    server generation from InitExtensions(),  
                                    which is called from the X server's       
                                    main() function after all output devices  
                                    have been initialized, but before any     
                                    input devices have been initialized.      
                                                                              
                                    PanoramiXNumScreens is set to the number  
                                    of physical screens. If only one physical 
                                    screen is present, the extension is       
                                    disabled, and PanoramiXExtensionInit()    
                                    returns without doing anything else.      
                                                                              
                                    The Xinerama extension is registered by   
                                    calling AddExtension().                   
                                                                              
                                    GC and Screen private indexes are         
                                    allocated, and both GC and Screen private 
                                    areas are allocated for each physical     
                                    screen. These hold Xinerama-specific      
                                    per-GC and per-Screen data. Each screen's 
                                    CreateGC and CloseScreen functions are    
                                    wrapped by XineramaCreateGC() and         
                                    XineramaCloseScreen() respectively. Some  
                                    new resource classes are created for      
                                    Xinerama drawables and GCs, and resource  
                                    types for Xinerama windows, pixmaps and   
                                    colormaps.                                
                                                                              
                                    A region (PanoramiXScreenRegion) is       
                                    initialized to be the union of the screen 
                                    regions. The relative positioning         
                                    information for the physical screens is   
                                    taken from the ScreenRec x and y members, 
                                    which the DDX layer must initialize in    
                                    InitOutput(). The bounds of the combined  
                                    screen is also calculated                 
                                    (PanoramiXPixWidth and                    
                                    PanoramiXPixHeight).                      
                                                                              
                                    The DIX layer has a list of function      
                                    pointers (ProcVector[]) that holds the    
                                    entry points for the functions that       
                                    process core protocol requests. The       
                                    requests that Xinerama must intercept and 
                                    break up into physical screen-specific    
                                    requests are wrapped. The original set is 
                                    copied to SavedProcVector[]. The types of 
                                    requests intercepted are Window requests, 
                                    GC requests, colormap requests, drawing   
                                    requests, and some geometry-related       
                                    requests. This wrapping allows the bulk   
                                    of the protocol request processing to be  
                                    handled transparently to the DIX layer.   
                                    Some operations cannot be dealt with in   
                                    this way and are handled with             
                                    Xinerama-specific code within the DIX     
                                    layer.                                    
   PanoramiXConsolidate()           PanoramiXConsolidate() is a               
                                    device-independent extension function     
                                    that is called directly from the X        
                                    server's main() function after extensions 
                                    and input/output devices have been        
                                    initialized, and before the root windows  
                                    are defined and initialized.              
                                                                              
                                    This function finds the set of depths     
                                    (PanoramiXDepths[]) and visuals           
                                    (PanoramiXVisuals[]) common to all of the 
                                    physical screens. PanoramiXNumDepths is   
                                    set to the number of common depths, and   
                                    PanoramiXNumVisuals is set to the number  
                                    of common visuals. Resources are created  
                                    for the single root window and the        
                                    default colormap. Each of these resources 
                                    has per-physical screen entries.          
   PanoramiXCreateConnectionBlock() PanoramiXConsolidate() is a               
                                    device-independent extension function     
                                    that is called directly from the X        
                                    server's main() function after the        
                                    per-physical screen root windows are      
                                    created. It is called instead of the      
                                    standard DIX CreateConnectionBlock()      
                                    function. If this function returns FALSE, 
                                    the X server exits with a fatal error.    
                                    This function will return FALSE if no     
                                    common depths were found in               
                                    PanoramiXConsolidate(). With no common    
                                    depths, Xinerama mode is not possible.    
                                                                              
                                    The connection block holds the            
                                    information that clients get when they    
                                    open a connection to the X server. It     
                                    includes information such as the          
                                    supported pixmap formats, number of       
                                    screens and the sizes, depths, visuals,   
                                    default colormap information, etc, for    
                                    each of the screens (much of information  
                                    that xdpyinfo shows). The connection      
                                    block is initialized with the combined    
                                    single screen values that were calculated 
                                    in the above two functions.               
                                                                              
                                    The Xinerama extension allows the         
                                    registration of connection block callback 
                                    functions. The purpose of these is to     
                                    allow other extensions to do processing   
                                    at this point. These callbacks can be     
                                    registered by calling                     
                                    XineramaRegisterConnectionBlockCallback() 
                                    from the other extension's                
                                    ExtensionInit() function. Each registered 
                                    connection block callback is called at    
                                    the end of                                
                                    PanoramiXCreateConnectionBlock().         

    Xinerama-specific changes to the DIX code

   There are a few types of Xinerama-specific changes within the DIX code.
   The main ones are described here.

   Functions that deal with colormap or GC -related operations outside of the
   intercepted protocol requests have a test added to only do the processing
   for screen numbers > 0. This is because they are handled for the single
   Xinerama screen and the processing is done once for screen 0.

   The handling of motion events does some coordinate translation between the
   physical screen's origin and screen zero's origin. Also, motion events
   must be reported relative to the composite screen origin rather than the
   physical screen origins.

   There is some special handling for cursor, window and event processing
   that cannot (either not at all or not conveniently) be done via the
   intercepted protocol requests. A particular case is the handling of
   pointers moving between physical screens.

    Xinerama-specific changes to the MI code

   The only Xinerama-specific change to the MI code is in miSendExposures()
   to handle the coordinate (and window ID) translation for expose events.

    Intercepted DIX core requests

   Xinerama breaks up drawing requests for dispatch to each physical screen.
   It also breaks up windows into pieces for each physical screen. GCs are
   translated into per-screen GCs. Colormaps are replicated on each physical
   screen. The functions handling the intercepted requests take care of
   breaking the requests and repackaging them so that they can be passed to
   the standard request handling functions for each screen in turn. In
   addition, and to aid the repackaging, the information from many of the
   intercepted requests is used to keep up to date the necessary state
   information for the single composite screen. Requests (usually those with
   replies) that can be satisfied completely from this stored state
   information do not call the standard request handling functions.

Development Results

   In this section the results of each phase of development are discussed.
   This development took place between approximately June 2001 and July 2003.

  Phase I

   The initial development phase dealt with the basic implementation
   including the bootstrap code, which used the shadow framebuffer, and the
   unoptimized implementation, based on an Xnest-style implementation.

    Scope

   The goal of Phase I is to provide fundamental functionality that can act
   as a foundation for ongoing work:

    1. Develop the proxy X server

          o The proxy X server will operate on the X11 protocol and relay
            requests as necessary to correctly perform the request.

          o Work will be based on the existing work for Xinerama and Xnest.

          o Input events and windowing operations are handled in the proxy
            server and rendering requests are repackaged and sent to each of
            the back-end servers for display.

          o The multiple screen layout (including support for overlapping
            screens) will be user configurable via a configuration file or
            through the configuration tool.

    2. Develop graphical configuration tool

          o There will be potentially a large number of X servers to
            configure into a single display. The tool will allow the user to
            specify which servers are involved in the configuration and how
            they should be laid out.

    3. Pass the X Test Suite

          o The X Test Suite covers the basic X11 operations. All tests known
            to succeed must correctly operate in the distributed X
            environment.

   For this phase, the back-end X servers are assumed to be unmodified X
   servers that do not support any DMX-related protocol extensions; future
   optimization pathways are considered, but are not implemented; and the
   configuration tool is assumed to rely only on libraries in the X source
   tree (e.g., Xt).

    Results

   The proxy X server, Xdmx, was developed to distribute X11 protocol
   requests to the set of back-end X servers. It opens a window on each
   back-end server, which represents the part of the front-end's root window
   that is visible on that screen. It mirrors window, pixmap and other state
   in each back-end server. Drawing requests are sent to either windows or
   pixmaps on each back-end server. This code is based on Xnest and uses the
   existing Xinerama extension.

   Input events can be taken from (1) devices attached to the back-end
   server, (2) core devices attached directly to the Xdmx server, or (3) from
   a ``console'' window on another X server. Events for these devices are
   gathered, processed and delivered to clients attached to the Xdmx server.

   An intuitive configuration format was developed to help the user easily
   configure the multiple back-end X servers. It was defined (see grammar in
   Xdmx man page) and a parser was implemented that is used by the Xdmx
   server and by a standalone xdmxconfig utility. The parsing support was
   implemented such that it can be easily factored out of the X source tree
   for use with other tools (e.g., vdl). Support for converting legacy
   vdl-format configuration files to the DMX format is provided by the
   vdltodmx utility.

   Originally, the configuration file was going to be a subsection of
   XFree86's XF86Config file, but that was not possible since Xdmx is a
   completely separate X server. Thus, a separate config file format was
   developed. In addition, a graphical configuration tool, xdmxconfig, was
   developed to allow the user to create and arrange the screens in the
   configuration file. The -configfile and -config command-line options can
   be used to start Xdmx using a configuration file.

   An extension that enables remote input testing is required for the X Test
   Suite to function. During this phase, this extension (XTEST) was
   implemented in the Xdmx server. The results from running the X Test Suite
   are described in detail below.

    X Test Suite

      Introduction

   The X Test Suite contains tests that verify Xlib functions operate
   correctly. The test suite is designed to run on a single X server;
   however, since X applications will not be able to tell the difference
   between the DMX server and a standard X server, the X Test Suite should
   also run on the DMX server.

   The Xdmx server was tested with the X Test Suite, and the existing
   failures are noted in this section. To put these results in perspective,
   we first discuss expected X Test failures and how errors in underlying
   systems can impact Xdmx test results.

      Expected Failures for a Single Head

   A correctly implemented X server with a single screen is expected to fail
   certain X Test tests. The following well-known errors occur because of
   rounding error in the X server code:

   XDrawArc: Tests 42, 63, 66, 73
   XDrawArcs: Tests 45, 66, 69, 76
                 

   The following failures occur because of the high-level X server
   implementation:

   XLoadQueryFont: Test 1
   XListFontsWithInfo: Tests 3, 4
   XQueryFont: Tests 1, 2
                 

   The following test fails when running the X server as root under Linux
   because of the way directory modes are interpreted:

   XWriteBitmapFile: Test 3
                 

   Depending on the video card used for the back-end, other failures may also
   occur because of bugs in the low-level driver implementation. Over time,
   failures of this kind are usually fixed by XFree86, but will show up in
   Xdmx testing until then.

      Expected Failures for Xinerama

   Xinerama fails several X Test Suite tests because of design decisions made
   for the current implementation of Xinerama. Over time, many of these
   errors will be corrected by XFree86 and the group working on a new
   Xinerama implementation. Therefore, Xdmx will also share X Suite Test
   failures with Xinerama.

   We may be able to fix or work-around some of these failures at the Xdmx
   level, but this will require additional exploration that was not part of
   Phase I.

   Xinerama is constantly improving, and the list of Xinerama-related
   failures depends on XFree86 version and the underlying graphics hardware.
   We tested with a variety of hardware, including nVidia, S3, ATI Radeon,
   and Matrox G400 (in dual-head mode). The list below includes only those
   failures that appear to be from the Xinerama layer, and does not include
   failures listed in the previous section, or failures that appear to be
   from the low-level graphics driver itself:

   These failures were noted with multiple Xinerama configurations:

   XCopyPlane: Tests 13, 22, 31 (well-known Xinerama implementation issue)
   XSetFontPath: Test 4
   XGetDefault: Test 5
   XMatchVisualInfo: Test 1
                 

   These failures were noted only when using one dual-head video card with a
   4.2.99.x XFree86 server:

   XListPixmapFormats: Test 1
   XDrawRectangles: Test 45
                 

   These failures were noted only when using two video cards from different
   vendors with a 4.1.99.x XFree86 server:

   XChangeWindowAttributes: Test 32
   XCreateWindow: Test 30
   XDrawLine: Test 22
   XFillArc: Test 22
   XChangeKeyboardControl: Tests 9, 10
   XRebindKeysym: Test 1
                 

      Additional Failures from Xdmx

   When running Xdmx, no unexpected failures were noted. Since the Xdmx
   server is based on Xinerama, we expect to have most of the Xinerama
   failures present in the Xdmx server. Similarly, since the Xdmx server must
   rely on the low-level device drivers on each back-end server, we also
   expect that Xdmx will exhibit most of the back-end failures. Here is a
   summary:

   XListPixmapFormats: Test 1 (configuration dependent)
   XChangeWindowAttributes: Test 32
   XCreateWindow: Test 30
   XCopyPlane: Test 13, 22, 31
   XSetFontPath: Test 4
   XGetDefault: Test 5 (configuration dependent)
   XMatchVisualInfo: Test 1
   XRebindKeysym: Test 1 (configuration dependent)
                   

   Note that this list is shorter than the combined list for Xinerama because
   Xdmx uses different code paths to perform some Xinerama operations.
   Further, some Xinerama failures have been fixed in the XFree86 4.2.99.x
   CVS repository.

      Summary and Future Work

   Running the X Test Suite on Xdmx does not produce any failures that cannot
   be accounted for by the underlying Xinerama subsystem used by the
   front-end or by the low-level device-driver code running on the back-end X
   servers. The Xdmx server therefore is as ``correct'' as possible with
   respect to the standard set of X Test Suite tests.

   During the following phases, we will continue to verify Xdmx correctness
   using the X Test Suite. We may also use other tests suites or write
   additional tests that run under the X Test Suite that specifically verify
   the expected behavior of DMX.

    Fonts

   In Phase I, fonts are handled directly by both the front-end and the
   back-end servers, which is required since we must treat each back-end
   server during this phase as a ``black box''. What this requires is that
   the front- and back-end servers must share the exact same font path. There
   are two ways to help make sure that all servers share the same font path:

    1. First, each server can be configured to use the same font server. The
       font server, xfs, can be configured to serve fonts to multiple X
       servers via TCP.

    2. Second, each server can be configured to use the same font path and
       either those font paths can be copied to each back-end machine or they
       can be mounted (e.g., via NFS) on each back-end machine.

   One additional concern is that a client program can set its own font path,
   and if it does so, then that font path must be available on each back-end
   machine.

   The -fontpath command line option was added to allow users to initialize
   the font path of the front end server. This font path is propagated to
   each back-end server when the default font is loaded. If there are any
   problems, an error message is printed, which will describe the problem and
   list the current font path. For more information about setting the font
   path, see the -fontpath option description in the man page.

    Performance

   Phase I of development was not intended to optimize performance. Its focus
   was on completely and correctly handling the base X11 protocol in the Xdmx
   server. However, several insights were gained during Phase I, which are
   listed here for reference during the next phase of development.

    1. Calls to XSync() can slow down rendering since it requires a complete
       round trip to and from a back-end server. This is especially
       problematic when communicating over long haul networks.

    2. Sending drawing requests to only the screens that they overlap should
       improve performance.

    Pixmaps

   Pixmaps were originally expected to be handled entirely in the front-end X
   server; however, it was found that this overly complicated the rendering
   code and would have required sending potentially large images to each back
   server that required them when copying from pixmap to screen. Thus, pixmap
   state is mirrored in the back-end server just as it is with regular window
   state. With this implementation, the same rendering code that draws to
   windows can be used to draw to pixmaps on the back-end server, and no
   large image transfers are required to copy from pixmap to window.

  Phase II

   The second phase of development concentrates on performance optimizations.
   These optimizations are documented here, with x11perf data to show how the
   optimizations improve performance.

   All benchmarks were performed by running Xdmx on a dual processor 1.4GHz
   AMD Athlon machine with 1GB of RAM connecting over 100baseT to two
   single-processor 1GHz Pentium III machines with 256MB of RAM and ATI Rage
   128 (RF) video cards. The front end was running Linux 2.4.20-pre1-ac1 and
   the back ends were running Linux 2.4.7-10 and version 4.2.99.1 of XFree86
   pulled from the XFree86 CVS repository on August 7, 2002. All systems were
   running Red Hat Linux 7.2.

    Moving from XFree86 4.1.99.1 to 4.2.0.0

   For phase II, the working source tree was moved to the branch tagged with
   dmx-1-0-branch and was updated from version 4.1.99.1 (20 August 2001) of
   the XFree86 sources to version 4.2.0.0 (18 January 2002). After this
   update, the following tests were noted to be more than 10% faster:

 1.13   Fill 300x300 opaque stippled trapezoid (161x145 stipple)
 1.16   Fill 1x1 tiled trapezoid (161x145 tile)
 1.13   Fill 10x10 tiled trapezoid (161x145 tile)
 1.17   Fill 100x100 tiled trapezoid (161x145 tile)
 1.16   Fill 1x1 tiled trapezoid (216x208 tile)
 1.20   Fill 10x10 tiled trapezoid (216x208 tile)
 1.15   Fill 100x100 tiled trapezoid (216x208 tile)
 1.37   Circulate Unmapped window (200 kids)

   And the following tests were noted to be more than 10% slower:

 0.88   Unmap window via parent (25 kids)
 0.75   Circulate Unmapped window (4 kids)
 0.79   Circulate Unmapped window (16 kids)
 0.80   Circulate Unmapped window (25 kids)
 0.82   Circulate Unmapped window (50 kids)
 0.85   Circulate Unmapped window (75 kids)

   These changes were not caused by any changes in the DMX system, and may
   point to changes in the XFree86 tree or to tests that have more "jitter"
   than most other x11perf tests.

    Global changes

   During the development of the Phase II DMX server, several global changes
   were made. These changes were also compared with the Phase I server. The
   following tests were noted to be more than 10% faster:

 1.13   Fill 300x300 opaque stippled trapezoid (161x145 stipple)
 1.15   Fill 1x1 tiled trapezoid (161x145 tile)
 1.13   Fill 10x10 tiled trapezoid (161x145 tile)
 1.17   Fill 100x100 tiled trapezoid (161x145 tile)
 1.16   Fill 1x1 tiled trapezoid (216x208 tile)
 1.19   Fill 10x10 tiled trapezoid (216x208 tile)
 1.15   Fill 100x100 tiled trapezoid (216x208 tile)
 1.15   Circulate Unmapped window (4 kids)

   The following tests were noted to be more than 10% slower:

 0.69   Scroll 10x10 pixels
 0.68   Scroll 100x100 pixels
 0.68   Copy 10x10 from window to window
 0.68   Copy 100x100 from window to window
 0.76   Circulate Unmapped window (75 kids)
 0.83   Circulate Unmapped window (100 kids)

   For the remainder of this analysis, the baseline of comparison will be the
   Phase II deliverable with all optimizations disabled (unless otherwise
   noted). This will highlight how the optimizations in isolation impact
   performance.

    XSync() Batching

   During the Phase I implementation, XSync() was called after every protocol
   request made by the DMX server. This provided the DMX server with an
   interactive feel, but defeated X11's protocol buffering system and
   introduced round-trip wire latency into every operation. During Phase II,
   DMX was changed so that protocol requests are no longer followed by calls
   to XSync(). Instead, the need for an XSync() is noted, and XSync() calls
   are only made every 100mS or when the DMX server specifically needs to
   make a call to guarantee interactivity. With this new system, X11 buffers
   protocol as much as possible during a 100mS interval, and many unnecessary
   XSync() calls are avoided.

   Out of more than 300 x11perf tests, 8 tests became more than 100 times
   faster, with 68 more than 50X faster, 114 more than 10X faster, and 181
   more than 2X faster. See table below for summary.

   The following tests were noted to be more than 10% slower with XSync()
   batching on:

 0.88   500x500 tiled rectangle (161x145 tile)
 0.89   Copy 500x500 from window to window

    Offscreen Optimization

   Windows span one or more of the back-end servers' screens; however, during
   Phase I development, windows were created on every back-end server and
   every rendering request was sent to every window regardless of whether or
   not that window was visible. With the offscreen optimization, the DMX
   server tracks when a window is completely off of a back-end server's
   screen and, in that case, it does not send rendering requests to those
   back-end windows. This optimization saves bandwidth between the front and
   back-end servers, and it reduces the number of XSync() calls. The
   performance tests were run on a DMX system with only two back-end servers.
   Greater performance gains will be had as the number of back-end servers
   increases.

   Out of more than 300 x11perf tests, 3 tests were at least twice as fast,
   and 146 tests were at least 10% faster. Two tests were more than 10%
   slower with the offscreen optimization:

 0.88   Hide/expose window via popup (4 kids)
 0.89   Resize unmapped window (75 kids)

    Lazy Window Creation Optimization

   As mentioned above, during Phase I, windows were created on every back-end
   server even if they were not visible on that back-end. With the lazy
   window creation optimization, the DMX server does not create windows on a
   back-end server until they are either visible or they become the parents
   of a visible window. This optimization builds on the offscreen
   optimization (described above) and requires it to be enabled.

   The lazy window creation optimization works by creating the window data
   structures in the front-end server when a client creates a window, but
   delays creation of the window on the back-end server(s). A private window
   structure in the DMX server saves the relevant window data and tracks
   changes to the window's attributes and stacking order for later use. The
   only times a window is created on a back-end server are (1) when it is
   mapped and is at least partially overlapping the back-end server's screen
   (tracked by the offscreen optimization), or (2) when the window becomes
   the parent of a previously visible window. The first case occurs when a
   window is mapped or when a visible window is copied, moved or resized and
   now overlaps the back-end server's screen. The second case occurs when
   starting a window manager after having created windows to which the window
   manager needs to add decorations.

   When either case occurs, a window on the back-end server is created using
   the data saved in the DMX server's window private data structure. The
   stacking order is then adjusted to correctly place the window on the
   back-end and lastly the window is mapped. From this time forward, the
   window is handled exactly as if the window had been created at the time of
   the client's request.

   Note that when a window is no longer visible on a back-end server's screen
   (e.g., it is moved offscreen), the window is not destroyed; rather, it is
   kept and reused later if the window once again becomes visible on the
   back-end server's screen. Originally with this optimization, destroying
   windows was implemented but was later rejected because it increased
   bandwidth when windows were opaquely moved or resized, which is common in
   many window managers.

   The performance tests were run on a DMX system with only two back-end
   servers. Greater performance gains will be had as the number of back-end
   servers increases.

   This optimization improved the following x11perf tests by more than 10%:

 1.10   500x500 rectangle outline
 1.12   Fill 100x100 stippled trapezoid (161x145 stipple)
 1.20   Circulate Unmapped window (50 kids)
 1.19   Circulate Unmapped window (75 kids)

    Subdividing Rendering Primitives

   X11 imaging requests transfer significant data between the client and the
   X server. During Phase I, the DMX server would then transfer the image
   data to each back-end server. Even with the offscreen optimization
   (above), these requests still required transferring significant data to
   each back-end server that contained a visible portion of the window. For
   example, if the client uses XPutImage() to copy an image to a window that
   overlaps the entire DMX screen, then the entire image is copied by the DMX
   server to every back-end server.

   To reduce the amount of data transferred between the DMX server and the
   back-end servers when XPutImage() is called, the image data is subdivided
   and only the data that will be visible on a back-end server's screen is
   sent to that back-end server. Xinerama already implements a subdivision
   algorithm for XGetImage() and no further optimization was needed.

   Other rendering primitives were analyzed, but the time required to
   subdivide these primitives was a significant proportion of the time
   required to send the entire rendering request to the back-end server, so
   this optimization was rejected for the other rendering primitives.

   Again, the performance tests were run on a DMX system with only two
   back-end servers. Greater performance gains will be had as the number of
   back-end servers increases.

   This optimization improved the following x11perf tests by more than 10%:

 1.12   Fill 100x100 stippled trapezoid (161x145 stipple)
 1.26   PutImage 10x10 square
 1.83   PutImage 100x100 square
 1.91   PutImage 500x500 square
 1.40   PutImage XY 10x10 square
 1.48   PutImage XY 100x100 square
 1.50   PutImage XY 500x500 square
 1.45   Circulate Unmapped window (75 kids)
 1.74   Circulate Unmapped window (100 kids)

   The following test was noted to be more than 10% slower with this
   optimization:

 0.88   10-pixel fill chord partial circle

    Summary of x11perf Data

   With all of the optimizations on, 53 x11perf tests are more than 100X
   faster than the unoptimized Phase II deliverable, with 69 more than 50X
   faster, 73 more than 10X faster, and 199 more than twice as fast. No tests
   were more than 10% slower than the unoptimized Phase II deliverable.
   (Compared with the Phase I deliverable, only Circulate Unmapped window
   (100 kids) was more than 10% slower than the Phase II deliverable. As
   noted above, this test seems to have wider variability than other x11perf
   tests.)

   The following table summarizes relative x11perf test changes for all
   optimizations individually and collectively. Note that some of the
   optimizations have a synergistic effect when used together.


 1: XSync() batching only
 2: Off screen optimizations only
 3: Window optimizations only
 4: Subdivprims only
 5: All optimizations

     1     2    3    4      5 Operation
 ------ ---- ---- ---- ------ ---------
   2.14 1.85 1.00 1.00   4.13 Dot
   1.67 1.80 1.00 1.00   3.31 1x1 rectangle
   2.38 1.43 1.00 1.00   2.44 10x10 rectangle
   1.00 1.00 0.92 0.98   1.00 100x100 rectangle
   1.00 1.00 1.00 1.00   1.00 500x500 rectangle
   1.83 1.85 1.05 1.06   3.54 1x1 stippled rectangle (8x8 stipple)
   2.43 1.43 1.00 1.00   2.41 10x10 stippled rectangle (8x8 stipple)
   0.98 1.00 1.00 1.00   1.00 100x100 stippled rectangle (8x8 stipple)
   1.00 1.00 1.00 1.00   0.98 500x500 stippled rectangle (8x8 stipple)
   1.75 1.75 1.00 1.00   3.40 1x1 opaque stippled rectangle (8x8 stipple)
   2.38 1.42 1.00 1.00   2.34 10x10 opaque stippled rectangle (8x8 stipple)
   1.00 1.00 0.97 0.97   1.00 100x100 opaque stippled rectangle (8x8 stipple)
   1.00 1.00 1.00 1.00   0.99 500x500 opaque stippled rectangle (8x8 stipple)
   1.82 1.82 1.04 1.04   3.56 1x1 tiled rectangle (4x4 tile)
   2.33 1.42 1.00 1.00   2.37 10x10 tiled rectangle (4x4 tile)
   1.00 0.92 1.00 1.00   1.00 100x100 tiled rectangle (4x4 tile)
   1.00 1.00 1.00 1.00   1.00 500x500 tiled rectangle (4x4 tile)
   1.94 1.62 1.00 1.00   3.66 1x1 stippled rectangle (17x15 stipple)
   1.74 1.28 1.00 1.00   1.73 10x10 stippled rectangle (17x15 stipple)
   1.00 1.00 1.00 0.89   0.98 100x100 stippled rectangle (17x15 stipple)
   1.00 1.00 1.00 1.00   0.98 500x500 stippled rectangle (17x15 stipple)
   1.94 1.62 1.00 1.00   3.67 1x1 opaque stippled rectangle (17x15 stipple)
   1.69 1.26 1.00 1.00   1.66 10x10 opaque stippled rectangle (17x15 stipple)
   1.00 0.95 1.00 1.00   1.00 100x100 opaque stippled rectangle (17x15 stipple)
   1.00 1.00 1.00 1.00   0.97 500x500 opaque stippled rectangle (17x15 stipple)
   1.93 1.61 0.99 0.99   3.69 1x1 tiled rectangle (17x15 tile)
   1.73 1.27 1.00 1.00   1.72 10x10 tiled rectangle (17x15 tile)
   1.00 1.00 1.00 1.00   0.98 100x100 tiled rectangle (17x15 tile)
   1.00 1.00 0.97 0.97   1.00 500x500 tiled rectangle (17x15 tile)
   1.95 1.63 1.00 1.00   3.83 1x1 stippled rectangle (161x145 stipple)
   1.80 1.30 1.00 1.00   1.83 10x10 stippled rectangle (161x145 stipple)
   0.97 1.00 1.00 1.00   1.01 100x100 stippled rectangle (161x145 stipple)
   1.00 1.00 1.00 1.00   0.98 500x500 stippled rectangle (161x145 stipple)
   1.95 1.63 1.00 1.00   3.56 1x1 opaque stippled rectangle (161x145 stipple)
   1.65 1.25 1.00 1.00   1.68 10x10 opaque stippled rectangle (161x145 stipple)
   1.00 1.00 1.00 1.00   1.01 100x100 opaque stippled rectangle (161x145...
   1.00 1.00 1.00 1.00   0.97 500x500 opaque stippled rectangle (161x145...
   1.95 1.63 0.98 0.99   3.80 1x1 tiled rectangle (161x145 tile)
   1.67 1.26 1.00 1.00   1.67 10x10 tiled rectangle (161x145 tile)
   1.13 1.14 1.14 1.14   1.14 100x100 tiled rectangle (161x145 tile)
   0.88 1.00 1.00 1.00   0.99 500x500 tiled rectangle (161x145 tile)
   1.93 1.63 1.00 1.00   3.53 1x1 tiled rectangle (216x208 tile)
   1.69 1.26 1.00 1.00   1.66 10x10 tiled rectangle (216x208 tile)
   1.00 1.00 1.00 1.00   1.00 100x100 tiled rectangle (216x208 tile)
   1.00 1.00 1.00 1.00   1.00 500x500 tiled rectangle (216x208 tile)
   1.82 1.70 1.00 1.00   3.38 1-pixel line segment
   2.07 1.56 0.90 1.00   3.31 10-pixel line segment
   1.29 1.10 1.00 1.00   1.27 100-pixel line segment
   1.05 1.06 1.03 1.03   1.09 500-pixel line segment
   1.30 1.13 1.00 1.00   1.29 100-pixel line segment (1 kid)
   1.32 1.15 1.00 1.00   1.32 100-pixel line segment (2 kids)
   1.33 1.16 1.00 1.00   1.33 100-pixel line segment (3 kids)
   1.92 1.64 1.00 1.00   3.73 10-pixel dashed segment
   1.34 1.16 1.00 1.00   1.34 100-pixel dashed segment
   1.24 1.11 0.99 0.97   1.23 100-pixel double-dashed segment
   1.72 1.77 1.00 1.00   3.25 10-pixel horizontal line segment
   1.83 1.66 1.01 1.00   3.54 100-pixel horizontal line segment
   1.86 1.30 1.00 1.00   1.84 500-pixel horizontal line segment
   2.11 1.52 1.00 0.99   3.02 10-pixel vertical line segment
   1.21 1.10 1.00 1.00   1.20 100-pixel vertical line segment
   1.03 1.03 1.00 1.00   1.02 500-pixel vertical line segment
   4.42 1.68 1.00 1.01   4.64 10x1 wide horizontal line segment
   1.83 1.31 1.00 1.00   1.83 100x10 wide horizontal line segment
   1.07 1.00 0.96 1.00   1.07 500x50 wide horizontal line segment
   4.10 1.67 1.00 1.00   4.62 10x1 wide vertical line segment
   1.50 1.24 1.06 1.06   1.48 100x10 wide vertical line segment
   1.06 1.03 1.00 1.00   1.05 500x50 wide vertical line segment
   2.54 1.61 1.00 1.00   3.61 1-pixel line
   2.71 1.48 1.00 1.00   2.67 10-pixel line
   1.19 1.09 1.00 1.00   1.19 100-pixel line
   1.04 1.02 1.00 1.00   1.03 500-pixel line
   2.68 1.51 0.98 1.00   3.17 10-pixel dashed line
   1.23 1.11 0.99 0.99   1.23 100-pixel dashed line
   1.15 1.08 1.00 1.00   1.15 100-pixel double-dashed line
   2.27 1.39 1.00 1.00   2.23 10x1 wide line
   1.20 1.09 1.00 1.00   1.20 100x10 wide line
   1.04 1.02 1.00 1.00   1.04 500x50 wide line
   1.52 1.45 1.00 1.00   1.52 100x10 wide dashed line
   1.54 1.47 1.00 1.00   1.54 100x10 wide double-dashed line
   1.97 1.30 0.96 0.95   1.95 10x10 rectangle outline
   1.44 1.27 1.00 1.00   1.43 100x100 rectangle outline
   3.22 2.16 1.10 1.09   3.61 500x500 rectangle outline
   1.95 1.34 1.00 1.00   1.90 10x10 wide rectangle outline
   1.14 1.14 1.00 1.00   1.13 100x100 wide rectangle outline
   1.00 1.00 1.00 1.00   1.00 500x500 wide rectangle outline
   1.57 1.72 1.00 1.00   3.03 1-pixel circle
   1.96 1.35 1.00 1.00   1.92 10-pixel circle
   1.21 1.07 0.86 0.97   1.20 100-pixel circle
   1.08 1.04 1.00 1.00   1.08 500-pixel circle
   1.39 1.19 1.03 1.03   1.38 100-pixel dashed circle
   1.21 1.11 1.00 1.00   1.23 100-pixel double-dashed circle
   1.59 1.28 1.00 1.00   1.58 10-pixel wide circle
   1.22 1.12 0.99 1.00   1.22 100-pixel wide circle
   1.06 1.04 1.00 1.00   1.05 500-pixel wide circle
   1.87 1.84 1.00 1.00   1.85 100-pixel wide dashed circle
   1.90 1.93 1.01 1.01   1.90 100-pixel wide double-dashed circle
   2.13 1.43 1.00 1.00   2.32 10-pixel partial circle
   1.42 1.18 1.00 1.00   1.42 100-pixel partial circle
   1.92 1.85 1.01 1.01   1.89 10-pixel wide partial circle
   1.73 1.67 1.00 1.00   1.73 100-pixel wide partial circle
   1.36 1.95 1.00 1.00   2.64 1-pixel solid circle
   2.02 1.37 1.00 1.00   2.03 10-pixel solid circle
   1.19 1.09 1.00 1.00   1.19 100-pixel solid circle
   1.02 0.99 1.00 1.00   1.01 500-pixel solid circle
   1.74 1.28 1.00 0.88   1.73 10-pixel fill chord partial circle
   1.31 1.13 1.00 1.00   1.31 100-pixel fill chord partial circle
   1.67 1.31 1.03 1.03   1.72 10-pixel fill slice partial circle
   1.30 1.13 1.00 1.00   1.28 100-pixel fill slice partial circle
   2.45 1.49 1.01 1.00   2.71 10-pixel ellipse
   1.22 1.10 1.00 1.00   1.22 100-pixel ellipse
   1.09 1.04 1.00 1.00   1.09 500-pixel ellipse
   1.90 1.28 1.00 1.00   1.89 100-pixel dashed ellipse
   1.62 1.24 0.96 0.97   1.61 100-pixel double-dashed ellipse
   2.43 1.50 1.00 1.00   2.42 10-pixel wide ellipse
   1.61 1.28 1.03 1.03   1.60 100-pixel wide ellipse
   1.08 1.05 1.00 1.00   1.08 500-pixel wide ellipse
   1.93 1.88 1.00 1.00   1.88 100-pixel wide dashed ellipse
   1.94 1.89 1.01 1.00   1.94 100-pixel wide double-dashed ellipse
   2.31 1.48 1.00 1.00   2.67 10-pixel partial ellipse
   1.38 1.17 1.00 1.00   1.38 100-pixel partial ellipse
   2.00 1.85 0.98 0.97   1.98 10-pixel wide partial ellipse
   1.89 1.86 1.00 1.00   1.89 100-pixel wide partial ellipse
   3.49 1.60 1.00 1.00   3.65 10-pixel filled ellipse
   1.67 1.26 1.00 1.00   1.67 100-pixel filled ellipse
   1.06 1.04 1.00 1.00   1.06 500-pixel filled ellipse
   2.38 1.43 1.01 1.00   2.32 10-pixel fill chord partial ellipse
   2.06 1.30 1.00 1.00   2.05 100-pixel fill chord partial ellipse
   2.27 1.41 1.00 1.00   2.27 10-pixel fill slice partial ellipse
   1.98 1.33 1.00 0.97   1.97 100-pixel fill slice partial ellipse
  57.46 1.99 1.01 1.00 114.92 Fill 1x1 equivalent triangle
  56.94 1.98 1.01 1.00  73.89 Fill 10x10 equivalent triangle
   6.07 1.75 1.00 1.00   6.07 Fill 100x100 equivalent triangle
  51.12 1.98 1.00 1.00 102.81 Fill 1x1 trapezoid
  51.42 1.82 1.01 1.00  94.89 Fill 10x10 trapezoid
   6.47 1.80 1.00 1.00   6.44 Fill 100x100 trapezoid
   1.56 1.28 1.00 0.99   1.56 Fill 300x300 trapezoid
  51.27 1.97 0.96 0.97 102.54 Fill 1x1 stippled trapezoid (8x8 stipple)
  51.73 2.00 1.02 1.02  67.92 Fill 10x10 stippled trapezoid (8x8 stipple)
   5.36 1.72 1.00 1.00   5.36 Fill 100x100 stippled trapezoid (8x8 stipple)
   1.54 1.26 1.00 1.00   1.59 Fill 300x300 stippled trapezoid (8x8 stipple)
  51.41 1.94 1.01 1.00 102.82 Fill 1x1 opaque stippled trapezoid (8x8 stipple)
  50.71 1.95 0.99 1.00  65.44 Fill 10x10 opaque stippled trapezoid (8x8...
   5.33 1.73 1.00 1.00   5.36 Fill 100x100 opaque stippled trapezoid (8x8...
   1.58 1.25 1.00 1.00   1.58 Fill 300x300 opaque stippled trapezoid (8x8...
  51.56 1.96 0.99 0.90 103.68 Fill 1x1 tiled trapezoid (4x4 tile)
  51.59 1.99 1.01 1.01  62.25 Fill 10x10 tiled trapezoid (4x4 tile)
   5.38 1.72 1.00 1.00   5.38 Fill 100x100 tiled trapezoid (4x4 tile)
   1.54 1.25 1.00 0.99   1.58 Fill 300x300 tiled trapezoid (4x4 tile)
  51.70 1.98 1.01 1.01 103.98 Fill 1x1 stippled trapezoid (17x15 stipple)
  44.86 1.97 1.00 1.00  44.86 Fill 10x10 stippled trapezoid (17x15 stipple)
   2.74 1.56 1.00 1.00   2.73 Fill 100x100 stippled trapezoid (17x15 stipple)
   1.29 1.14 1.00 1.00   1.27 Fill 300x300 stippled trapezoid (17x15 stipple)
  51.41 1.96 0.96 0.95 103.39 Fill 1x1 opaque stippled trapezoid (17x15...
  45.14 1.96 1.01 1.00  45.14 Fill 10x10 opaque stippled trapezoid (17x15...
   2.68 1.56 1.00 1.00   2.68 Fill 100x100 opaque stippled trapezoid (17x15...
   1.26 1.10 1.00 1.00   1.28 Fill 300x300 opaque stippled trapezoid (17x15...
  51.13 1.97 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (17x15 tile)
  47.58 1.96 1.00 1.00  47.86 Fill 10x10 tiled trapezoid (17x15 tile)
   2.74 1.56 1.00 1.00   2.74 Fill 100x100 tiled trapezoid (17x15 tile)
   1.29 1.14 1.00 1.00   1.28 Fill 300x300 tiled trapezoid (17x15 tile)
  51.13 1.97 0.99 0.97 103.39 Fill 1x1 stippled trapezoid (161x145 stipple)
  45.14 1.97 1.00 1.00  44.29 Fill 10x10 stippled trapezoid (161x145 stipple)
   3.02 1.77 1.12 1.12   3.38 Fill 100x100 stippled trapezoid (161x145 stipple)
   1.31 1.13 1.00 1.00   1.30 Fill 300x300 stippled trapezoid (161x145 stipple)
  51.27 1.97 1.00 1.00 103.10 Fill 1x1 opaque stippled trapezoid (161x145...
  45.01 1.97 1.00 1.00  45.01 Fill 10x10 opaque stippled trapezoid (161x145...
   2.67 1.56 1.00 1.00   2.69 Fill 100x100 opaque stippled trapezoid (161x145..
   1.29 1.13 1.00 1.01   1.27 Fill 300x300 opaque stippled trapezoid (161x145..
  51.41 1.96 1.00 0.99 103.39 Fill 1x1 tiled trapezoid (161x145 tile)
  45.01 1.96 0.98 1.00  45.01 Fill 10x10 tiled trapezoid (161x145 tile)
   2.62 1.36 1.00 1.00   2.69 Fill 100x100 tiled trapezoid (161x145 tile)
   1.27 1.13 1.00 1.00   1.22 Fill 300x300 tiled trapezoid (161x145 tile)
  51.13 1.98 1.00 1.00 103.39 Fill 1x1 tiled trapezoid (216x208 tile)
  45.14 1.97 1.01 0.99  45.14 Fill 10x10 tiled trapezoid (216x208 tile)
   2.62 1.55 1.00 1.00   2.71 Fill 100x100 tiled trapezoid (216x208 tile)
   1.28 1.13 1.00 1.00   1.20 Fill 300x300 tiled trapezoid (216x208 tile)
  50.71 1.95 1.00 1.00  54.70 Fill 10x10 equivalent complex polygon
   5.51 1.71 0.96 0.98   5.47 Fill 100x100 equivalent complex polygons
   8.39 1.97 1.00 1.00  16.75 Fill 10x10 64-gon (Convex)
   8.38 1.83 1.00 1.00   8.43 Fill 100x100 64-gon (Convex)
   8.50 1.96 1.00 1.00  16.64 Fill 10x10 64-gon (Complex)
   8.26 1.83 1.00 1.00   8.35 Fill 100x100 64-gon (Complex)
  14.09 1.87 1.00 1.00  14.05 Char in 80-char line (6x13)
  11.91 1.87 1.00 1.00  11.95 Char in 70-char line (8x13)
  11.16 1.85 1.01 1.00  11.10 Char in 60-char line (9x15)
  10.09 1.78 1.00 1.00  10.09 Char16 in 40-char line (k14)
   6.15 1.75 1.00 1.00   6.31 Char16 in 23-char line (k24)
  11.92 1.90 1.03 1.03  11.88 Char in 80-char line (TR 10)
   8.18 1.78 1.00 0.99   8.17 Char in 30-char line (TR 24)
  42.83 1.44 1.01 1.00  42.11 Char in 20/40/20 line (6x13, TR 10)
  27.45 1.43 1.01 1.01  27.45 Char16 in 7/14/7 line (k14, k24)
  12.13 1.85 1.00 1.00  12.05 Char in 80-char image line (6x13)
  10.00 1.84 1.00 1.00  10.00 Char in 70-char image line (8x13)
   9.18 1.83 1.00 1.00   9.12 Char in 60-char image line (9x15)
   9.66 1.82 0.98 0.95   9.66 Char16 in 40-char image line (k14)
   5.82 1.72 1.00 1.00   5.99 Char16 in 23-char image line (k24)
   8.70 1.80 1.00 1.00   8.65 Char in 80-char image line (TR 10)
   4.67 1.66 1.00 1.00   4.67 Char in 30-char image line (TR 24)
  84.43 1.47 1.00 1.00 124.18 Scroll 10x10 pixels
   3.73 1.50 1.00 0.98   3.73 Scroll 100x100 pixels
   1.00 1.00 1.00 1.00   1.00 Scroll 500x500 pixels
  84.43 1.51 1.00 1.00 134.02 Copy 10x10 from window to window
   3.62 1.51 0.98 0.98   3.62 Copy 100x100 from window to window
   0.89 1.00 1.00 1.00   1.00 Copy 500x500 from window to window
  57.06 1.99 1.00 1.00  88.64 Copy 10x10 from pixmap to window
   2.49 2.00 1.00 1.00   2.48 Copy 100x100 from pixmap to window
   1.00 0.91 1.00 1.00   0.98 Copy 500x500 from pixmap to window
   2.04 1.01 1.00 1.00   2.03 Copy 10x10 from window to pixmap
   1.05 1.00 1.00 1.00   1.05 Copy 100x100 from window to pixmap
   1.00 1.00 0.93 1.00   1.04 Copy 500x500 from window to pixmap
  58.52 1.03 1.03 1.02  57.95 Copy 10x10 from pixmap to pixmap
   2.40 1.00 1.00 1.00   2.45 Copy 100x100 from pixmap to pixmap
   1.00 1.00 1.00 1.00   1.00 Copy 500x500 from pixmap to pixmap
  51.57 1.92 1.00 1.00  85.75 Copy 10x10 1-bit deep plane
   6.37 1.75 1.01 1.01   6.37 Copy 100x100 1-bit deep plane
   1.26 1.11 1.00 1.00   1.24 Copy 500x500 1-bit deep plane
   4.23 1.63 0.98 0.97   4.38 Copy 10x10 n-bit deep plane
   1.04 1.02 1.00 1.00   1.04 Copy 100x100 n-bit deep plane
   1.00 1.00 1.00 1.00   1.00 Copy 500x500 n-bit deep plane
   6.45 1.98 1.00 1.26  12.80 PutImage 10x10 square
   1.10 1.87 1.00 1.83   2.11 PutImage 100x100 square
   1.02 1.93 1.00 1.91   1.91 PutImage 500x500 square
   4.17 1.78 1.00 1.40   7.18 PutImage XY 10x10 square
   1.27 1.49 0.97 1.48   2.10 PutImage XY 100x100 square
   1.00 1.50 1.00 1.50   1.52 PutImage XY 500x500 square
   1.07 1.01 1.00 1.00   1.06 GetImage 10x10 square
   1.01 1.00 1.00 1.00   1.01 GetImage 100x100 square
   1.00 1.00 1.00 1.00   1.00 GetImage 500x500 square
   1.56 1.00 0.99 0.97   1.56 GetImage XY 10x10 square
   1.02 1.00 1.00 1.00   1.02 GetImage XY 100x100 square
   1.00 1.00 1.00 1.00   1.00 GetImage XY 500x500 square
   1.00 1.00 1.01 0.98   0.95 X protocol NoOperation
   1.02 1.03 1.04 1.03   1.00 QueryPointer
   1.03 1.02 1.04 1.03   1.00 GetProperty
 100.41 1.51 1.00 1.00 198.76 Change graphics context
  45.81 1.00 0.99 0.97  57.10 Create and map subwindows (4 kids)
  78.45 1.01 1.02 1.02  63.07 Create and map subwindows (16 kids)
  73.91 1.01 1.00 1.00  56.37 Create and map subwindows (25 kids)
  73.22 1.00 1.00 1.00  49.07 Create and map subwindows (50 kids)
  72.36 1.01 0.99 1.00  32.14 Create and map subwindows (75 kids)
  70.34 1.00 1.00 1.00  30.12 Create and map subwindows (100 kids)
  55.00 1.00 1.00 0.99  23.75 Create and map subwindows (200 kids)
  55.30 1.01 1.00 1.00 141.03 Create unmapped window (4 kids)
  55.38 1.01 1.01 1.00 163.25 Create unmapped window (16 kids)
  54.75 0.96 1.00 0.99 166.95 Create unmapped window (25 kids)
  54.83 1.00 1.00 0.99 178.81 Create unmapped window (50 kids)
  55.38 1.01 1.01 1.00 181.20 Create unmapped window (75 kids)
  55.38 1.01 1.01 1.00 181.20 Create unmapped window (100 kids)
  54.87 1.01 1.01 1.00 182.05 Create unmapped window (200 kids)
  28.13 1.00 1.00 1.00  30.75 Map window via parent (4 kids)
  36.14 1.01 1.01 1.01  32.58 Map window via parent (16 kids)
  26.13 1.00 0.98 0.95  29.85 Map window via parent (25 kids)
  40.07 1.00 1.01 1.00  27.57 Map window via parent (50 kids)
  23.26 0.99 1.00 1.00  18.23 Map window via parent (75 kids)
  22.91 0.99 1.00 0.99  16.52 Map window via parent (100 kids)
  27.79 1.00 1.00 0.99  12.50 Map window via parent (200 kids)
  22.35 1.00 1.00 1.00  56.19 Unmap window via parent (4 kids)
   9.57 1.00 0.99 1.00  89.78 Unmap window via parent (16 kids)
  80.77 1.01 1.00 1.00 103.85 Unmap window via parent (25 kids)
  96.34 1.00 1.00 1.00 116.06 Unmap window via parent (50 kids)
  99.72 1.00 1.00 1.00 124.93 Unmap window via parent (75 kids)
 112.36 1.00 1.00 1.00 125.27 Unmap window via parent (100 kids)
 105.41 1.00 1.00 0.99 120.00 Unmap window via parent (200 kids)
  51.29 1.03 1.02 1.02  74.19 Destroy window via parent (4 kids)
  86.75 0.99 0.99 0.99 116.87 Destroy window via parent (16 kids)
 106.43 1.01 1.01 1.01 127.49 Destroy window via parent (25 kids)
 120.34 1.01 1.01 1.00 140.11 Destroy window via parent (50 kids)
 126.67 1.00 0.99 0.99 145.00 Destroy window via parent (75 kids)
 126.11 1.01 1.01 1.00 140.56 Destroy window via parent (100 kids)
 128.57 1.01 1.00 1.00 137.91 Destroy window via parent (200 kids)
  16.04 0.88 1.00 1.00  20.36 Hide/expose window via popup (4 kids)
  19.04 1.01 1.00 1.00  23.48 Hide/expose window via popup (16 kids)
  19.22 1.00 1.00 1.00  20.44 Hide/expose window via popup (25 kids)
  17.41 1.00 0.91 0.97  17.68 Hide/expose window via popup (50 kids)
  17.29 1.01 1.00 1.01  17.07 Hide/expose window via popup (75 kids)
  16.74 1.00 1.00 1.00  16.17 Hide/expose window via popup (100 kids)
  10.30 1.00 1.00 1.00  10.51 Hide/expose window via popup (200 kids)
  16.48 1.01 1.00 1.00  26.05 Move window (4 kids)
  17.01 0.95 1.00 1.00  23.97 Move window (16 kids)
  16.95 1.00 1.00 1.00  22.90 Move window (25 kids)
  16.05 1.01 1.00 1.00  21.32 Move window (50 kids)
  15.58 1.00 0.98 0.98  19.44 Move window (75 kids)
  14.98 1.02 1.03 1.03  18.17 Move window (100 kids)
  10.90 1.01 1.01 1.00  12.68 Move window (200 kids)
  49.42 1.00 1.00 1.00 198.27 Moved unmapped window (4 kids)
  50.72 0.97 1.00 1.00 193.66 Moved unmapped window (16 kids)
  50.87 1.00 0.99 1.00 195.09 Moved unmapped window (25 kids)
  50.72 1.00 1.00 1.00 189.34 Moved unmapped window (50 kids)
  50.87 1.00 1.00 1.00 191.33 Moved unmapped window (75 kids)
  50.87 1.00 1.00 0.90 186.71 Moved unmapped window (100 kids)
  50.87 1.00 1.00 1.00 179.19 Moved unmapped window (200 kids)
  41.04 1.00 1.00 1.00  56.61 Move window via parent (4 kids)
  69.81 1.00 1.00 1.00 130.82 Move window via parent (16 kids)
  95.81 1.00 1.00 1.00 141.92 Move window via parent (25 kids)
  95.98 1.00 1.00 1.00 149.43 Move window via parent (50 kids)
  96.59 1.01 1.01 1.00 153.98 Move window via parent (75 kids)
  97.19 1.00 1.00 1.00 157.30 Move window via parent (100 kids)
  96.67 1.00 0.99 0.96 159.44 Move window via parent (200 kids)
  17.75 1.01 1.00 1.00  27.61 Resize window (4 kids)
  17.94 1.00 1.00 0.99  25.42 Resize window (16 kids)
  17.92 1.01 1.00 1.00  24.47 Resize window (25 kids)
  17.24 0.97 1.00 1.00  24.14 Resize window (50 kids)
  16.81 1.00 1.00 0.99  22.75 Resize window (75 kids)
  16.08 1.00 1.00 1.00  21.20 Resize window (100 kids)
  12.92 1.00 0.99 1.00  16.26 Resize window (200 kids)
  52.94 1.01 1.00 1.00 327.12 Resize unmapped window (4 kids)
  53.60 1.01 1.01 1.01 333.71 Resize unmapped window (16 kids)
  52.99 1.00 1.00 1.00 337.29 Resize unmapped window (25 kids)
  51.98 1.00 1.00 1.00 329.38 Resize unmapped window (50 kids)
  53.05 0.89 1.00 1.00 322.60 Resize unmapped window (75 kids)
  53.05 1.00 1.00 1.00 318.08 Resize unmapped window (100 kids)
  53.11 1.00 1.00 0.99 306.21 Resize unmapped window (200 kids)
  16.76 1.00 0.96 1.00  19.46 Circulate window (4 kids)
  17.24 1.00 1.00 0.97  16.24 Circulate window (16 kids)
  16.30 1.03 1.03 1.03  15.85 Circulate window (25 kids)
  13.45 1.00 1.00 1.00  14.90 Circulate window (50 kids)
  12.91 1.00 1.00 1.00  13.06 Circulate window (75 kids)
  11.30 0.98 1.00 1.00  11.03 Circulate window (100 kids)
   7.58 1.01 1.01 0.99   7.47 Circulate window (200 kids)
   1.01 1.01 0.98 1.00   0.95 Circulate Unmapped window (4 kids)
   1.07 1.07 1.01 1.07   1.02 Circulate Unmapped window (16 kids)
   1.04 1.09 1.06 1.05   0.97 Circulate Unmapped window (25 kids)
   1.04 1.23 1.20 1.18   1.05 Circulate Unmapped window (50 kids)
   1.18 1.53 1.19 1.45   1.24 Circulate Unmapped window (75 kids)
   1.08 1.02 1.01 1.74   1.01 Circulate Unmapped window (100 kids)
   1.01 1.12 0.98 0.91   0.97 Circulate Unmapped window (200 kids)

    Profiling with OProfile

   OProfile (available from http://oprofile.sourceforge.net/) is a
   system-wide profiler for Linux systems that uses processor-level counters
   to collect sampling data. OProfile can provide information that is similar
   to that provided by gprof, but without the necessity of recompiling the
   program with special instrumentation (i.e., OProfile can collect
   statistical profiling information about optimized programs). A test
   harness was developed to collect OProfile data for each x11perf test
   individually.

   Test runs were performed using the RETIRED_INSNS counter on the AMD Athlon
   and the CPU_CLK_HALTED counter on the Intel Pentium III (with a test
   configuration different from the one described above). We have examined
   OProfile output and have compared it with gprof output. This investigation
   has not produced results that yield performance increases in x11perf
   numbers.

    X Test Suite

   The X Test Suite was run on the fully optimized DMX server using the
   configuration described above. The following failures were noted:

 XListPixmapFormats: Test 1              [1]
 XChangeWindowAttributes: Test 32        [1]
 XCreateWindow: Test 30                  [1]
 XFreeColors: Test 4                     [3]
 XCopyArea: Test 13, 17, 21, 25, 30      [2]
 XCopyPlane: Test 11, 15, 27, 31         [2]
 XSetFontPath: Test 4                    [1]
 XChangeKeyboardControl: Test 9, 10      [1]

 [1] Previously documented errors expected from the Xinerama
     implementation (see Phase I discussion).
 [2] Newly noted errors that have been verified as expected
     behavior of the Xinerama implementation.
 [3] Newly noted error that has been verified as a Xinerama
     implementation bug.

  Phase III

   During the third phase of development, support was provided for the
   following extensions: SHAPE, RENDER, XKEYBOARD, XInput.

    SHAPE

   The SHAPE extension is supported. Test applications (e.g., xeyes and
   oclock) and window managers that make use of the SHAPE extension will work
   as expected.

    RENDER

   The RENDER extension is supported. The version included in the DMX CVS
   tree is version 0.2, and this version is fully supported by Xdmx.
   Applications using only version 0.2 functions will work correctly;
   however, some apps that make use of functions from later versions do not
   properly check the extension's major/minor version numbers. These apps
   will fail with a Bad Implementation error when using post-version 0.2
   functions. This is expected behavior. When the DMX CVS tree is updated to
   include newer versions of RENDER, support for these newer functions will
   be added to the DMX X server.

    XKEYBOARD

   The XKEYBOARD extension is supported. If present on the back-end X
   servers, the XKEYBOARD extension will be used to obtain information about
   the type of the keyboard for initialization. Otherwise, the keyboard will
   be initialized using defaults. Note that this departs from older behavior:
   when Xdmx is compiled without XKEYBOARD support, the map from the back-end
   X server will be preserved. With XKEYBOARD support, the map is not
   preserved because better information and control of the keyboard is
   available.

    XInput

   The XInput extension is supported. Any device can be used as a core device
   and be used as an XInput extension device, with the exception of core
   devices on the back-end servers. This limitation is present because cursor
   handling on the back-end requires that the back-end cursor sometimes track
   the Xdmx core cursor -- behavior that is incompatible with using the
   back-end pointer as a non-core device.

   Currently, back-end extension devices are not available as Xdmx extension
   devices, but this limitation should be removed in the future.

   To demonstrate the XInput extension, and to provide more examples for
   low-level input device driver writers, USB device drivers have been
   written for mice (usb-mou), keyboards (usb-kbd), and
   non-mouse/non-keyboard USB devices (usb-oth). Please see the man page for
   information on Linux kernel drivers that are required for using these Xdmx
   drivers.

    DPMS

   The DPMS extension is exported but does not do anything at this time.

    Other Extensions

   The LBX, SECURITY, XC-APPGROUP, and XFree86-Bigfont extensions do not
   require any special Xdmx support and have been exported.

   The BIG-REQUESTS, DEC-XTRAP, DOUBLE-BUFFER, Extended-Visual-Information,
   FontCache, GLX, MIT-SCREEN-SAVER, MIT-SHM, MIT-SUNDRY-NONSTANDARD, RECORD,
   SECURITY, SGI-GLX, SYNC, TOG-CUP, X-Resource, XC-MISC, XFree86-DGA,
   XFree86-DRI, XFree86-Misc, XFree86-VidModeExtension, and XVideo extensions
   are not supported at this time, but will be evaluated for inclusion in
   future DMX releases. See below for additional work on extensions after
   Phase III.

  Phase IV

    Moving to XFree86 4.3.0

   For Phase IV, the recent release of XFree86 4.3.0 (27 February 2003) was
   merged onto the dmx.sourceforge.net CVS trunk and all work is proceeding
   using this tree.

    Extensions

      XC-MISC (supported)

   XC-MISC is used internally by the X library to recycle XIDs from the X
   server. This is important for long-running X server sessions. Xdmx
   supports this extension. The X Test Suite passed and failed the exact same
   tests before and after this extension was enabled.

      Extended-Visual-Information (supported)

   The Extended-Visual-Information extension provides a method for an X
   client to obtain detailed visual information. Xdmx supports this
   extension. It was tested using the hw/dmx/examples/evi example program.
   Note that this extension is not Xinerama-aware -- it will return visual
   information for each screen even though Xinerama is causing the X server
   to export a single logical screen.

      RES (supported)

   The X-Resource extension provides a mechanism for a client to obtain
   detailed information about the resources used by other clients. This
   extension was tested with the hw/dmx/examples/res program. The X Test
   Suite passed and failed the exact same tests before and after this
   extension was enabled.

      BIG-REQUESTS (supported)

   This extension enables the X11 protocol to handle requests longer than
   262140 bytes. The X Test Suite passed and failed the exact same tests
   before and after this extension was enabled.

      XSYNC (supported)

   This extension provides facilities for two different X clients to
   synchronize their requests. This extension was minimally tested with
   xdpyinfo and the X Test Suite passed and failed the exact same tests
   before and after this extension was enabled.

      XTEST, RECORD, DEC-XTRAP (supported) and XTestExtension1 (not supported)

   The XTEST and RECORD extension were developed by the X Consortium for use
   in the X Test Suite and are supported as a standard in the X11R6 tree.
   They are also supported in Xdmx. When X Test Suite tests that make use of
   the XTEST extension are run, Xdmx passes and fails exactly the same tests
   as does a standard XFree86 X server. When the rcrdtest test (a part of the
   X Test Suite that verifies the RECORD extension) is run, Xdmx passes and
   fails exactly the same tests as does a standard XFree86 X server.

   There are two older XTEST-like extensions: DEC-XTRAP and XTestExtension1.
   The XTestExtension1 extension was developed for use by the X Testing
   Consortium for use with a test suite that eventually became (part of?) the
   X Test Suite. Unlike XTEST, which only allows events to be sent to the
   server, the XTestExtension1 extension also allowed events to be recorded
   (similar to the RECORD extension). The second is the DEC-XTRAP extension
   that was developed by the Digital Equipment Corporation.

   The DEC-XTRAP extension is available from Xdmx and has been tested with
   the xtrap* tools which are distributed as standard X11R6 clients.

   The XTestExtension1 is not supported because it does not appear to be used
   by any modern X clients (the few that support it also support XTEST) and
   because there are no good methods available for testing that it functions
   correctly (unlike XTEST and DEC-XTRAP, the code for XTestExtension1 is not
   part of the standard X server source tree, so additional testing is
   important).

   Most of these extensions are documented in the X11R6 source tree. Further,
   several original papers exist that this author was unable to locate -- for
   completeness and historical interest, citations are provide:

   XRECORD         Martha Zimet. Extending X For Recording. 8th Annual X      
                   Technical Conference Boston, MA January 24-26, 1994.       
   DEC-XTRAP       Dick Annicchiarico, Robert Chesler, Alan Jamison. XTrap    
                   Architecture. Digital Equipment Corporation, July 1991.    
   XTestExtension1 Larry Woestman. X11 Input Synthesis Extension Proposal.    
                   Hewlett Packard, November 1991.                            

      MIT-MISC (not supported)

   The MIT-MISC extension is used to control a bug-compatibility flag that
   provides compatibility with xterm programs from X11R1 and X11R2. There
   does not appear to be a single client available that makes use of this
   extension and there is not way to verify that it works correctly. The Xdmx
   server does not support MIT-MISC.

      SCREENSAVER (not supported)

   This extension provides special support for the X screen saver. It was
   tested with beforelight, which appears to be the only client that works
   with it. When Xinerama was not active, beforelight behaved as expected.
   However, when Xinerama was active, beforelight did not behave as expected.
   Further, when this extension is not active, xscreensaver (a widely-used X
   screen saver program) did not behave as expected. Since this extension is
   not Xinerama-aware and is not commonly used with expected results by
   clients, we have left this extension disabled at this time.

      GLX (supported)

   The GLX extension provides OpenGL and GLX windowing support. In Xdmx, the
   extension is called glxProxy, and it is Xinerama aware. It works by either
   feeding requests forward through Xdmx to each of the back-end servers or
   handling them locally. All rendering requests are handled on the back-end
   X servers. This code was donated to the DMX project by SGI. For the X Test
   Suite results comparison, see below.

      RENDER (supported)

   The X Rendering Extension (RENDER) provides support for digital image
   composition. Geometric and text rendering are supported. RENDER is
   partially Xinerama-aware, with text and the most basic compositing
   operator; however, its higher level primitives (triangles, triangle
   strips, and triangle fans) are not yet Xinerama-aware. The RENDER
   extension is still under development, and is currently at version 0.8.
   Additional support will be required in DMX as more primitives and/or
   requests are added to the extension.

   There is currently no test suite for the X Rendering Extension; however,
   there has been discussion of developing a test suite as the extension
   matures. When that test suite becomes available, additional testing can be
   performed with Xdmx. The X Test Suite passed and failed the exact same
   tests before and after this extension was enabled.

      Summary

   To summarize, the following extensions are currently supported:
   BIG-REQUESTS, DEC-XTRAP, DMX, DPMS, Extended-Visual-Information, GLX, LBX,
   RECORD, RENDER, SECURITY, SHAPE, SYNC, X-Resource, XC-APPGROUP, XC-MISC,
   XFree86-Bigfont, XINERAMA, XInputExtension, XKEYBOARD, and XTEST.

   The following extensions are not supported at this time: DOUBLE-BUFFER,
   FontCache, MIT-SCREEN-SAVER, MIT-SHM, MIT-SUNDRY-NONSTANDARD, TOG-CUP,
   XFree86-DGA, XFree86-Misc, XFree86-VidModeExtension, XTestExtensionExt1,
   and XVideo.

    Additional Testing with the X Test Suite

      XFree86 without XTEST

   After the release of XFree86 4.3.0, we retested the XFree86 X server with
   and without using the XTEST extension. When the XTEST extension was not
   used for testing, the XFree86 4.3.0 server running on our usual test
   system with a Radeon VE card reported unexpected failures in the following
   tests:

   XListPixmapFormats: Test 1
   XChangeKeyboardControl: Tests 9, 10
   XGetDefault: Test 5
   XRebindKeysym: Test 1

      XFree86 with XTEST

   When using the XTEST extension, the XFree86 4.3.0 server reported the
   following errors:

   XListPixmapFormats: Test 1
   XChangeKeyboardControl: Tests 9, 10
   XGetDefault: Test 5
   XRebindKeysym: Test 1

   XAllowEvents: Tests 20, 21, 24
   XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25
   XGrabKey: Test 8
   XSetPointerMapping: Test 3
   XUngrabButton: Test 4

   While these errors may be important, they will probably be fixed
   eventually in the XFree86 source tree. We are particularly interested in
   demonstrating that the Xdmx server does not introduce additional failures
   that are not known Xinerama failures.

      Xdmx with XTEST, without Xinerama, without GLX

   Without Xinerama, but using the XTEST extension, the following errors were
   reported from Xdmx (note that these are the same as for the XFree86 4.3.0,
   except that XGetDefault no longer fails):

   XListPixmapFormats: Test 1
   XChangeKeyboardControl: Tests 9, 10
   XRebindKeysym: Test 1

   XAllowEvents: Tests  20, 21, 24
   XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25
   XGrabKey: Test 8
   XSetPointerMapping: Test 3
   XUngrabButton: Test 4

      Xdmx with XTEST, with Xinerama, without GLX

   With Xinerama, using the XTEST extension, the following errors were
   reported from Xdmx:

   XListPixmapFormats: Test 1
   XChangeKeyboardControl: Tests 9, 10
   XRebindKeysym: Test 1

   XAllowEvents: Tests 20, 21, 24
   XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25
   XGrabKey: Test 8
   XSetPointerMapping: Test 3
   XUngrabButton: Test 4

   XCopyPlane: Tests 13, 22, 31 (well-known XTEST/Xinerama interaction issue)
   XDrawLine: Test 67
   XDrawLines: Test 91
   XDrawSegments: Test 68

   Note that the first two sets of errors are the same as for the XFree86
   4.3.0 server, and that the XCopyPlane error is a well-known error
   resulting from an XTEST/Xinerama interaction when the request crosses a
   screen boundary. The XDraw* errors are resolved when the tests are run
   individually and they do not cross a screen boundary. We will investigate
   these errors further to determine their cause.

      Xdmx with XTEST, with Xinerama, with GLX

   With GLX enabled, using the XTEST extension, the following errors were
   reported from Xdmx (these results are from early during the Phase IV
   development, but were confirmed with a late Phase IV snapshot):

   XListPixmapFormats: Test 1
   XChangeKeyboardControl: Tests 9, 10
   XRebindKeysym: Test 1

   XAllowEvents: Tests 20, 21, 24
   XGrabButton: Tests 5, 9-12, 14, 16, 19, 21-25
   XGrabKey: Test 8
   XSetPointerMapping: Test 3
   XUngrabButton: Test 4

   XClearArea: Test 8
   XCopyArea: Tests 4, 5, 11, 14, 17, 23, 25, 27, 30
   XCopyPlane: Tests 6, 7, 10, 19, 22, 31
   XDrawArcs: Tests 89, 100, 102
   XDrawLine: Test 67
   XDrawSegments: Test 68

   Note that the first two sets of errors are the same as for the XFree86
   4.3.0 server, and that the third set has different failures than when Xdmx
   does not include GLX support. Since the GLX extension adds new visuals to
   support GLX's visual configs and the X Test Suite runs tests over the
   entire set of visuals, additional rendering tests were run and presumably
   more of them crossed a screen boundary. This conclusion is supported by
   the fact that nearly all of the rendering errors reported are resolved
   when the tests are run individually and they do no cross a screen
   boundary.

   Further, when hardware rendering is disabled on the back-end displays,
   many of the errors in the third set are eliminated, leaving only:

   XClearArea: Test 8
   XCopyArea: Test 4, 5, 11, 14, 17, 23, 25, 27, 30
   XCopyPlane: Test 6, 7, 10, 19, 22, 31

      Conclusion

   We conclude that all of the X Test Suite errors reported for Xdmx are the
   result of errors in the back-end X server or the Xinerama implementation.
   Further, all of these errors that can be reasonably fixed at the Xdmx
   layer have been. (Where appropriate, we have submitted patches to the
   XFree86 and Xinerama upstream maintainers.)

    Dynamic Reconfiguration

   During this development phase, dynamic reconfiguration support was added
   to DMX. This support allows an application to change the position and
   offset of a back-end server's screen. For example, if the application
   would like to shift a screen slightly to the left, it could query Xdmx for
   the screen's <x,y> position and then dynamically reconfigure that screen
   to be at position <x+10,y>. When a screen is dynamically reconfigured,
   input handling and a screen's root window dimensions are adjusted as
   needed. These adjustments are transparent to the user.

      Dynamic reconfiguration extension

   The application interface to DMX's dynamic reconfiguration is through a
   function in the DMX extension library:

 Bool DMXReconfigureScreen(Display *dpy, int screen, int x, int y)

   where dpy is DMX server's display, screen is the number of the screen to
   be reconfigured, and x and y are the new upper, left-hand coordinates of
   the screen to be reconfigured.

   The coordinates are not limited other than as required by the X protocol,
   which limits all coordinates to a signed 16 bit number. In addition, all
   coordinates within a screen must also be legal values. Therefore, setting
   a screen's upper, left-hand coordinates such that the right or bottom
   edges of the screen is greater than 32,767 is illegal.

      Bounding box

   When the Xdmx server is started, a bounding box is calculated from the
   screens' layout given either on the command line or in the configuration
   file. This bounding box is currently fixed for the lifetime of the Xdmx
   server.

   While it is possible to move a screen outside of the bounding box, it is
   currently not possible to change the dimensions of the bounding box. For
   example, it is possible to specify coordinates of <-100,-100> for the
   upper, left-hand corner of the bounding box, which was previously at
   coordinates <0,0>. As expected, the screen is moved down and to the right;
   however, since the bounding box is fixed, the left side and upper portions
   of the screen exposed by the reconfiguration are no longer accessible on
   that screen. Those inaccessible regions are filled with black.

   This fixed bounding box limitation will be addressed in a future
   development phase.

      Sample applications

   An example of where this extension is useful is in setting up a video
   wall. It is not always possible to get everything perfectly aligned, and
   sometimes the positions are changed (e.g., someone might bump into a
   projector). Instead of physically moving projectors or monitors, it is now
   possible to adjust the positions of the back-end server's screens using
   the dynamic reconfiguration support in DMX.

   Other applications, such as automatic setup and calibration tools, can
   make use of dynamic reconfiguration to correct for projector alignment
   problems, as long as the projectors are still arranged rectilinearly.
   Horizontal and vertical keystone correction could be applied to projectors
   to correct for non-rectilinear alignment problems; however, this must be
   done external to Xdmx.

   A sample test program is included in the DMX server's examples directory
   to demonstrate the interface and how an application might use dynamic
   reconfiguration. See dmxreconfig.c for details.

      Additional notes

   In the original development plan, Phase IV was primarily devoted to adding
   OpenGL support to DMX; however, SGI became interested in the DMX project
   and developed code to support OpenGL/GLX. This code was later donated to
   the DMX project and integrated into the DMX code base, which freed the DMX
   developers to concentrate on dynamic reconfiguration (as described above).

    Doxygen documentation

   Doxygen is an open-source (GPL) documentation system for generating
   browseable documentation from stylized comments in the source code. We
   have placed all of the Xdmx server and DMX protocol source code files
   under Doxygen so that comprehensive documentation for the Xdmx source code
   is available in an easily browseable format.

    Valgrind

   Valgrind, an open-source (GPL) memory debugger for Linux, was used to
   search for memory management errors. Several memory leaks were detected
   and repaired. The following errors were not addressed:

    1. When the X11 transport layer sends a reply to the client, only those
       fields that are required by the protocol are filled in -- unused
       fields are left as uninitialized memory and are therefore noted by
       valgrind. These instances are not errors and were not repaired.

    2. At each server generation, glxInitVisuals allocates memory that is
       never freed. The amount of memory lost each generation approximately
       equal to 128 bytes for each back-end visual. Because the code involved
       is automatically generated, this bug has not been fixed and will be
       referred to SGI.

    3. At each server generation, dmxRealizeFont calls XLoadQueryFont, which
       allocates a font structure that is not freed. dmxUnrealizeFont can
       free the font structure for the first screen, but cannot free it for
       the other screens since they are already closed by the time
       dmxUnrealizeFont could free them. The amount of memory lost each
       generation is approximately equal to 80 bytes per font per back-end.
       When this bug is fixed in the the X server's device-independent (dix)
       code, DMX will be able to properly free the memory allocated by
       XLoadQueryFont.

    RATS

   RATS (Rough Auditing Tool for Security) is an open-source (GPL) security
   analysis tool that scans source code for common security-related
   programming errors (e.g., buffer overflows and TOCTOU races). RATS was
   used to audit all of the code in the hw/dmx directory and all "High"
   notations were checked manually. The code was either re-written to
   eliminate the warning, or a comment containing "RATS" was inserted on the
   line to indicate that a human had checked the code. Unrepaired warnings
   are as follows:

    1. Fixed-size buffers are used in many areas, but code has been added to
       protect against buffer overflows (e.g., XmuSnprint). The only
       instances that have not yet been fixed are in config/xdmxconfig.c
       (which is not part of the Xdmx server) and input/usb-common.c.

    2. vprintf and vfprintf are used in the logging routines. In general, all
       uses of these functions (e.g., dmxLog) provide a constant format
       string from a trusted source, so the use is relatively benign.

    3. glxProxy/glxscreens.c uses getenv and strcat. The use of these
       functions is safe and will remain safe as long as ExtensionsString is
       longer then GLXServerExtensions (ensuring this may not be ovious to
       the casual programmer, but this is in automatically generated code, so
       we hope that the generator enforces this constraint).
contact: Jan Huwald // Impressum