1 /*
2
3 Copyright 1993, 1998 The Open Group
4
5 Permission to use, copy, modify, distribute, and sell this software and its
6 documentation for any purpose is hereby granted without fee, provided that
7 the above copyright notice appear in all copies and that both that
8 copyright notice and this permission notice appear in supporting
9 documentation.
10
11 The above copyright notice and this permission notice shall be included
12 in all copies or substantial portions of the Software.
13
14 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
15 OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16 MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
17 IN NO EVENT SHALL THE OPEN GROUP BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 OTHER DEALINGS IN THE SOFTWARE.
21
22 Except as contained in this notice, the name of The Open Group shall
23 not be used in advertising or otherwise to promote the sale, use or
24 other dealings in this Software without prior written authorization
25 from The Open Group.
26
27 */
28
29 #ifdef HAVE_DIX_CONFIG_H
30 #include <dix-config.h>
31 #endif
32
33 #if defined(WIN32)
34 #include <X11/Xwinsock.h>
35 #endif
36 #include <stdio.h>
37 #include <X11/X.h>
38 #include <X11/Xproto.h>
39 #include <X11/Xos.h>
40 #include "scrnintstr.h"
41 #include "servermd.h"
42 #define PSZ 8
43 #include "fb.h"
44 #include "colormapst.h"
45 #include "gcstruct.h"
46 #include "input.h"
47 #include "mipointer.h"
48 #include "micmap.h"
49 #include <sys/types.h>
50 #ifdef HAVE_MMAP
51 #include <sys/mman.h>
52 #ifndef MAP_FILE
53 #define MAP_FILE 0
54 #endif
55 #endif /* HAVE_MMAP */
56 #include <sys/stat.h>
57 #include <errno.h>
58 #ifndef WIN32
59 #include <sys/param.h>
60 #endif
61 #include <X11/XWDFile.h>
62 #ifdef HAS_SHM
63 #include <sys/ipc.h>
64 #include <sys/shm.h>
65 #endif /* HAS_SHM */
66 #include "dix.h"
67 #include "miline.h"
68 #include "glx_extinit.h"
69 #include "randrstr.h"
70
71 #define VFB_DEFAULT_WIDTH 1280
72 #define VFB_DEFAULT_HEIGHT 1024
73 #define VFB_DEFAULT_DEPTH 24
74 #define VFB_DEFAULT_WHITEPIXEL 1
75 #define VFB_DEFAULT_BLACKPIXEL 0
76 #define VFB_DEFAULT_LINEBIAS 0
77 #define XWD_WINDOW_NAME_LEN 60
78
79 typedef struct {
80 int width;
81 int paddedBytesWidth;
82 int paddedWidth;
83 int height;
84 int depth;
85 int bitsPerPixel;
86 int sizeInBytes;
87 int ncolors;
88 char *pfbMemory;
89 XWDColor *pXWDCmap;
90 XWDFileHeader *pXWDHeader;
91 Pixel blackPixel;
92 Pixel whitePixel;
93 unsigned int lineBias;
94 CloseScreenProcPtr closeScreen;
95
96 #ifdef HAVE_MMAP
97 int mmap_fd;
98 char mmap_file[MAXPATHLEN];
99 #endif
100
101 #ifdef HAS_SHM
102 int shmid;
103 #endif
104 } vfbScreenInfo, *vfbScreenInfoPtr;
105
106 static int vfbNumScreens;
107 static vfbScreenInfo *vfbScreens;
108
109 static vfbScreenInfo defaultScreenInfo = {
110 .width = VFB_DEFAULT_WIDTH,
111 .height = VFB_DEFAULT_HEIGHT,
112 .depth = VFB_DEFAULT_DEPTH,
113 .blackPixel = VFB_DEFAULT_BLACKPIXEL,
114 .whitePixel = VFB_DEFAULT_WHITEPIXEL,
115 .lineBias = VFB_DEFAULT_LINEBIAS,
116 };
117
118 static Bool vfbPixmapDepths[33];
119
120 #ifdef HAVE_MMAP
121 static char *pfbdir = NULL;
122 #endif
123 typedef enum { NORMAL_MEMORY_FB, SHARED_MEMORY_FB, MMAPPED_FILE_FB } fbMemType;
124 static fbMemType fbmemtype = NORMAL_MEMORY_FB;
125 static char needswap = 0;
126 static Bool Render = TRUE;
127
128 #define swapcopy16(_dst, _src) \
129 if (needswap) { CARD16 _s = _src; cpswaps(_s, _dst); } \
130 else _dst = _src;
131
132 #define swapcopy32(_dst, _src) \
133 if (needswap) { CARD32 _s = _src; cpswapl(_s, _dst); } \
134 else _dst = _src;
135
136 static void
vfbInitializePixmapDepths(void)137 vfbInitializePixmapDepths(void)
138 {
139 int i;
140
141 vfbPixmapDepths[1] = TRUE; /* always need bitmaps */
142 for (i = 2; i <= 32; i++)
143 vfbPixmapDepths[i] = FALSE;
144 }
145
146 static int
vfbBitsPerPixel(int depth)147 vfbBitsPerPixel(int depth)
148 {
149 if (depth == 1)
150 return 1;
151 else if (depth <= 8)
152 return 8;
153 else if (depth <= 16)
154 return 16;
155 else
156 return 32;
157 }
158
159 void
ddxGiveUp(enum ExitCode error)160 ddxGiveUp(enum ExitCode error)
161 {
162 int i;
163
164 /* clean up the framebuffers */
165
166 switch (fbmemtype) {
167 #ifdef HAVE_MMAP
168 case MMAPPED_FILE_FB:
169 for (i = 0; i < vfbNumScreens; i++) {
170 if (-1 == unlink(vfbScreens[i].mmap_file)) {
171 perror("unlink");
172 ErrorF("unlink %s failed, %s",
173 vfbScreens[i].mmap_file, strerror(errno));
174 }
175 }
176 break;
177 #else /* HAVE_MMAP */
178 case MMAPPED_FILE_FB:
179 break;
180 #endif /* HAVE_MMAP */
181
182 #ifdef HAS_SHM
183 case SHARED_MEMORY_FB:
184 for (i = 0; i < vfbNumScreens; i++) {
185 if (-1 == shmdt((char *) vfbScreens[i].pXWDHeader)) {
186 perror("shmdt");
187 ErrorF("shmdt failed, %s", strerror(errno));
188 }
189 }
190 break;
191 #else /* HAS_SHM */
192 case SHARED_MEMORY_FB:
193 break;
194 #endif /* HAS_SHM */
195
196 case NORMAL_MEMORY_FB:
197 for (i = 0; i < vfbNumScreens; i++) {
198 free(vfbScreens[i].pXWDHeader);
199 }
200 break;
201 }
202 }
203
204 void
AbortDDX(enum ExitCode error)205 AbortDDX(enum ExitCode error)
206 {
207 ddxGiveUp(error);
208 }
209
210 #ifdef __APPLE__
211 void
DarwinHandleGUI(int argc,char * argv[])212 DarwinHandleGUI(int argc, char *argv[])
213 {
214 }
215 #endif
216
217 void
OsVendorInit(void)218 OsVendorInit(void)
219 {
220 }
221
222 void
OsVendorFatalError(const char * f,va_list args)223 OsVendorFatalError(const char *f, va_list args)
224 {
225 }
226
227 #if defined(DDXBEFORERESET)
228 void
ddxBeforeReset(void)229 ddxBeforeReset(void)
230 {
231 return;
232 }
233 #endif
234
235 #if INPUTTHREAD
236 /** This function is called in Xserver/os/inputthread.c when starting
237 the input thread. */
238 void
ddxInputThreadInit(void)239 ddxInputThreadInit(void)
240 {
241 }
242 #endif
243
244 void
ddxUseMsg(void)245 ddxUseMsg(void)
246 {
247 ErrorF("-screen scrn WxHxD set screen's width, height, depth\n");
248 ErrorF("-pixdepths list-of-int support given pixmap depths\n");
249 ErrorF("+/-render turn on/off RENDER extension support"
250 "(default on)\n");
251 ErrorF("-linebias n adjust thin line pixelization\n");
252 ErrorF("-blackpixel n pixel value for black\n");
253 ErrorF("-whitepixel n pixel value for white\n");
254
255 #ifdef HAVE_MMAP
256 ErrorF
257 ("-fbdir directory put framebuffers in mmap'ed files in directory\n");
258 #endif
259
260 #ifdef HAS_SHM
261 ErrorF("-shmem put framebuffers in shared memory\n");
262 #endif
263 }
264
265 int
ddxProcessArgument(int argc,char * argv[],int i)266 ddxProcessArgument(int argc, char *argv[], int i)
267 {
268 static Bool firstTime = TRUE;
269 static int lastScreen = -1;
270 vfbScreenInfo *currentScreen;
271
272 if (firstTime) {
273 vfbInitializePixmapDepths();
274 firstTime = FALSE;
275 }
276
277 if (lastScreen == -1)
278 currentScreen = &defaultScreenInfo;
279 else
280 currentScreen = &vfbScreens[lastScreen];
281
282 #define CHECK_FOR_REQUIRED_ARGUMENTS(num) \
283 if (((i + num) >= argc) || (!argv[i + num])) { \
284 ErrorF("Required argument to %s not specified\n", argv[i]); \
285 UseMsg(); \
286 FatalError("Required argument to %s not specified\n", argv[i]); \
287 }
288
289 if (strcmp(argv[i], "-screen") == 0) { /* -screen n WxHxD */
290 int screenNum;
291
292 CHECK_FOR_REQUIRED_ARGUMENTS(2);
293 screenNum = atoi(argv[i + 1]);
294 /* The protocol only has a CARD8 for number of screens in the
295 connection setup block, so don't allow more than that. */
296 if ((screenNum < 0) || (screenNum >= 255)) {
297 ErrorF("Invalid screen number %d\n", screenNum);
298 UseMsg();
299 FatalError("Invalid screen number %d passed to -screen\n",
300 screenNum);
301 }
302
303 if (vfbNumScreens <= screenNum) {
304 vfbScreens =
305 reallocarray(vfbScreens, screenNum + 1, sizeof(*vfbScreens));
306 if (!vfbScreens)
307 FatalError("Not enough memory for screen %d\n", screenNum);
308 for (; vfbNumScreens <= screenNum; ++vfbNumScreens)
309 vfbScreens[vfbNumScreens] = defaultScreenInfo;
310 }
311
312 if (3 != sscanf(argv[i + 2], "%dx%dx%d",
313 &vfbScreens[screenNum].width,
314 &vfbScreens[screenNum].height,
315 &vfbScreens[screenNum].depth)) {
316 ErrorF("Invalid screen configuration %s\n", argv[i + 2]);
317 UseMsg();
318 FatalError("Invalid screen configuration %s for -screen %d\n",
319 argv[i + 2], screenNum);
320 }
321
322 lastScreen = screenNum;
323 return 3;
324 }
325
326 if (strcmp(argv[i], "-pixdepths") == 0) { /* -pixdepths list-of-depth */
327 int depth, ret = 1;
328
329 CHECK_FOR_REQUIRED_ARGUMENTS(1);
330 while ((++i < argc) && (depth = atoi(argv[i])) != 0) {
331 if (depth < 0 || depth > 32) {
332 ErrorF("Invalid pixmap depth %d\n", depth);
333 UseMsg();
334 FatalError("Invalid pixmap depth %d passed to -pixdepths\n",
335 depth);
336 }
337 vfbPixmapDepths[depth] = TRUE;
338 ret++;
339 }
340 return ret;
341 }
342
343 if (strcmp(argv[i], "+render") == 0) { /* +render */
344 Render = TRUE;
345 return 1;
346 }
347
348 if (strcmp(argv[i], "-render") == 0) { /* -render */
349 Render = FALSE;
350 #ifdef COMPOSITE
351 noCompositeExtension = TRUE;
352 #endif
353 return 1;
354 }
355
356 if (strcmp(argv[i], "-blackpixel") == 0) { /* -blackpixel n */
357 CHECK_FOR_REQUIRED_ARGUMENTS(1);
358 currentScreen->blackPixel = atoi(argv[++i]);
359 return 2;
360 }
361
362 if (strcmp(argv[i], "-whitepixel") == 0) { /* -whitepixel n */
363 CHECK_FOR_REQUIRED_ARGUMENTS(1);
364 currentScreen->whitePixel = atoi(argv[++i]);
365 return 2;
366 }
367
368 if (strcmp(argv[i], "-linebias") == 0) { /* -linebias n */
369 CHECK_FOR_REQUIRED_ARGUMENTS(1);
370 currentScreen->lineBias = atoi(argv[++i]);
371 return 2;
372 }
373
374 #ifdef HAVE_MMAP
375 if (strcmp(argv[i], "-fbdir") == 0) { /* -fbdir directory */
376 CHECK_FOR_REQUIRED_ARGUMENTS(1);
377 pfbdir = argv[++i];
378 fbmemtype = MMAPPED_FILE_FB;
379 return 2;
380 }
381 #endif /* HAVE_MMAP */
382
383 #ifdef HAS_SHM
384 if (strcmp(argv[i], "-shmem") == 0) { /* -shmem */
385 fbmemtype = SHARED_MEMORY_FB;
386 return 1;
387 }
388 #endif
389
390 return 0;
391 }
392
393 static void
vfbInstallColormap(ColormapPtr pmap)394 vfbInstallColormap(ColormapPtr pmap)
395 {
396 ColormapPtr oldpmap = GetInstalledmiColormap(pmap->pScreen);
397
398 if (pmap != oldpmap) {
399 int entries;
400 XWDFileHeader *pXWDHeader;
401 VisualPtr pVisual;
402 Pixel *ppix;
403 xrgb *prgb;
404 xColorItem *defs;
405 int i;
406
407 miInstallColormap(pmap);
408
409 entries = pmap->pVisual->ColormapEntries;
410 pXWDHeader = vfbScreens[pmap->pScreen->myNum].pXWDHeader;
411 pVisual = pmap->pVisual;
412
413 swapcopy32(pXWDHeader->visual_class, pVisual->class);
414 swapcopy32(pXWDHeader->red_mask, pVisual->redMask);
415 swapcopy32(pXWDHeader->green_mask, pVisual->greenMask);
416 swapcopy32(pXWDHeader->blue_mask, pVisual->blueMask);
417 swapcopy32(pXWDHeader->bits_per_rgb, pVisual->bitsPerRGBValue);
418 swapcopy32(pXWDHeader->colormap_entries, pVisual->ColormapEntries);
419
420 ppix = xallocarray(entries, sizeof(Pixel));
421 prgb = xallocarray(entries, sizeof(xrgb));
422 defs = xallocarray(entries, sizeof(xColorItem));
423
424 for (i = 0; i < entries; i++)
425 ppix[i] = i;
426 /* XXX truecolor */
427 QueryColors(pmap, entries, ppix, prgb, serverClient);
428
429 for (i = 0; i < entries; i++) { /* convert xrgbs to xColorItems */
430 defs[i].pixel = ppix[i] & 0xff; /* change pixel to index */
431 defs[i].red = prgb[i].red;
432 defs[i].green = prgb[i].green;
433 defs[i].blue = prgb[i].blue;
434 defs[i].flags = DoRed | DoGreen | DoBlue;
435 }
436 (*pmap->pScreen->StoreColors) (pmap, entries, defs);
437
438 free(ppix);
439 free(prgb);
440 free(defs);
441 }
442 }
443
444 static void
vfbStoreColors(ColormapPtr pmap,int ndef,xColorItem * pdefs)445 vfbStoreColors(ColormapPtr pmap, int ndef, xColorItem * pdefs)
446 {
447 XWDColor *pXWDCmap;
448 int i;
449
450 if (pmap != GetInstalledmiColormap(pmap->pScreen)) {
451 return;
452 }
453
454 pXWDCmap = vfbScreens[pmap->pScreen->myNum].pXWDCmap;
455
456 if ((pmap->pVisual->class | DynamicClass) == DirectColor) {
457 return;
458 }
459
460 for (i = 0; i < ndef; i++) {
461 if (pdefs[i].flags & DoRed) {
462 swapcopy16(pXWDCmap[pdefs[i].pixel].red, pdefs[i].red);
463 }
464 if (pdefs[i].flags & DoGreen) {
465 swapcopy16(pXWDCmap[pdefs[i].pixel].green, pdefs[i].green);
466 }
467 if (pdefs[i].flags & DoBlue) {
468 swapcopy16(pXWDCmap[pdefs[i].pixel].blue, pdefs[i].blue);
469 }
470 }
471 }
472
473 static Bool
vfbSaveScreen(ScreenPtr pScreen,int on)474 vfbSaveScreen(ScreenPtr pScreen, int on)
475 {
476 return TRUE;
477 }
478
479 #ifdef HAVE_MMAP
480
481 /* this flushes any changes to the screens out to the mmapped file */
482 static void
vfbBlockHandler(void * blockData,void * timeout)483 vfbBlockHandler(void *blockData, void *timeout)
484 {
485 int i;
486
487 for (i = 0; i < vfbNumScreens; i++) {
488 #ifdef MS_ASYNC
489 if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
490 (size_t) vfbScreens[i].sizeInBytes, MS_ASYNC))
491 #else
492 /* silly NetBSD and who else? */
493 if (-1 == msync((caddr_t) vfbScreens[i].pXWDHeader,
494 (size_t) vfbScreens[i].sizeInBytes))
495 #endif
496 {
497 perror("msync");
498 ErrorF("msync failed, %s", strerror(errno));
499 }
500 }
501 }
502
503 static void
vfbWakeupHandler(void * blockData,int result)504 vfbWakeupHandler(void *blockData, int result)
505 {
506 }
507
508 static void
vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb)509 vfbAllocateMmappedFramebuffer(vfbScreenInfoPtr pvfb)
510 {
511 #define DUMMY_BUFFER_SIZE 65536
512 char dummyBuffer[DUMMY_BUFFER_SIZE];
513 int currentFileSize, writeThisTime;
514
515 snprintf(pvfb->mmap_file, sizeof(pvfb->mmap_file), "%s/Xvfb_screen%d",
516 pfbdir, (int) (pvfb - vfbScreens));
517 if (-1 == (pvfb->mmap_fd = open(pvfb->mmap_file, O_CREAT | O_RDWR, 0666))) {
518 perror("open");
519 ErrorF("open %s failed, %s", pvfb->mmap_file, strerror(errno));
520 return;
521 }
522
523 /* Extend the file to be the proper size */
524
525 memset(dummyBuffer, 0, DUMMY_BUFFER_SIZE);
526 for (currentFileSize = 0;
527 currentFileSize < pvfb->sizeInBytes;
528 currentFileSize += writeThisTime) {
529 writeThisTime = min(DUMMY_BUFFER_SIZE,
530 pvfb->sizeInBytes - currentFileSize);
531 if (-1 == write(pvfb->mmap_fd, dummyBuffer, writeThisTime)) {
532 perror("write");
533 ErrorF("write %s failed, %s", pvfb->mmap_file, strerror(errno));
534 return;
535 }
536 }
537
538 /* try to mmap the file */
539
540 pvfb->pXWDHeader = (XWDFileHeader *) mmap((caddr_t) NULL, pvfb->sizeInBytes,
541 PROT_READ | PROT_WRITE,
542 MAP_FILE | MAP_SHARED,
543 pvfb->mmap_fd, 0);
544 if (-1 == (long) pvfb->pXWDHeader) {
545 perror("mmap");
546 ErrorF("mmap %s failed, %s", pvfb->mmap_file, strerror(errno));
547 pvfb->pXWDHeader = NULL;
548 return;
549 }
550
551 if (!RegisterBlockAndWakeupHandlers(vfbBlockHandler, vfbWakeupHandler,
552 NULL)) {
553 pvfb->pXWDHeader = NULL;
554 }
555 }
556 #endif /* HAVE_MMAP */
557
558 #ifdef HAS_SHM
559 static void
vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb)560 vfbAllocateSharedMemoryFramebuffer(vfbScreenInfoPtr pvfb)
561 {
562 /* create the shared memory segment */
563
564 pvfb->shmid = shmget(IPC_PRIVATE, pvfb->sizeInBytes, IPC_CREAT | 0777);
565 if (pvfb->shmid < 0) {
566 perror("shmget");
567 ErrorF("shmget %d bytes failed, %s", pvfb->sizeInBytes,
568 strerror(errno));
569 return;
570 }
571
572 /* try to attach it */
573
574 pvfb->pXWDHeader = (XWDFileHeader *) shmat(pvfb->shmid, 0, 0);
575 if (-1 == (long) pvfb->pXWDHeader) {
576 perror("shmat");
577 ErrorF("shmat failed, %s", strerror(errno));
578 pvfb->pXWDHeader = NULL;
579 return;
580 }
581
582 ErrorF("screen %d shmid %d\n", (int) (pvfb - vfbScreens), pvfb->shmid);
583 }
584 #endif /* HAS_SHM */
585
586 static char *
vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb)587 vfbAllocateFramebufferMemory(vfbScreenInfoPtr pvfb)
588 {
589 if (pvfb->pfbMemory)
590 return pvfb->pfbMemory; /* already done */
591
592 pvfb->sizeInBytes = pvfb->paddedBytesWidth * pvfb->height;
593
594 /* Calculate how many entries in colormap. This is rather bogus, because
595 * the visuals haven't even been set up yet, but we need to know because we
596 * have to allocate space in the file for the colormap. The number 10
597 * below comes from the MAX_PSEUDO_DEPTH define in cfbcmap.c.
598 */
599
600 if (pvfb->depth <= 10) { /* single index colormaps */
601 pvfb->ncolors = 1 << pvfb->depth;
602 }
603 else { /* decomposed colormaps */
604 int nplanes_per_color_component = pvfb->depth / 3;
605
606 if (pvfb->depth % 3)
607 nplanes_per_color_component++;
608 pvfb->ncolors = 1 << nplanes_per_color_component;
609 }
610
611 /* add extra bytes for XWDFileHeader, window name, and colormap */
612
613 pvfb->sizeInBytes += SIZEOF(XWDheader) + XWD_WINDOW_NAME_LEN +
614 pvfb->ncolors * SIZEOF(XWDColor);
615
616 pvfb->pXWDHeader = NULL;
617 switch (fbmemtype) {
618 #ifdef HAVE_MMAP
619 case MMAPPED_FILE_FB:
620 vfbAllocateMmappedFramebuffer(pvfb);
621 break;
622 #else
623 case MMAPPED_FILE_FB:
624 break;
625 #endif
626
627 #ifdef HAS_SHM
628 case SHARED_MEMORY_FB:
629 vfbAllocateSharedMemoryFramebuffer(pvfb);
630 break;
631 #else
632 case SHARED_MEMORY_FB:
633 break;
634 #endif
635
636 case NORMAL_MEMORY_FB:
637 pvfb->pXWDHeader = (XWDFileHeader *) malloc(pvfb->sizeInBytes);
638 break;
639 }
640
641 if (pvfb->pXWDHeader) {
642 pvfb->pXWDCmap = (XWDColor *) ((char *) pvfb->pXWDHeader
643 + SIZEOF(XWDheader) +
644 XWD_WINDOW_NAME_LEN);
645 pvfb->pfbMemory = (char *) (pvfb->pXWDCmap + pvfb->ncolors);
646
647 return pvfb->pfbMemory;
648 }
649 else
650 return NULL;
651 }
652
653 static void
vfbWriteXWDFileHeader(ScreenPtr pScreen)654 vfbWriteXWDFileHeader(ScreenPtr pScreen)
655 {
656 vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
657 XWDFileHeader *pXWDHeader = pvfb->pXWDHeader;
658 char hostname[XWD_WINDOW_NAME_LEN];
659 unsigned long swaptest = 1;
660 int i;
661
662 needswap = *(char *) &swaptest;
663
664 pXWDHeader->header_size =
665 (char *) pvfb->pXWDCmap - (char *) pvfb->pXWDHeader;
666 pXWDHeader->file_version = XWD_FILE_VERSION;
667
668 pXWDHeader->pixmap_format = ZPixmap;
669 pXWDHeader->pixmap_depth = pvfb->depth;
670 pXWDHeader->pixmap_height = pXWDHeader->window_height = pvfb->height;
671 pXWDHeader->xoffset = 0;
672 pXWDHeader->byte_order = IMAGE_BYTE_ORDER;
673 pXWDHeader->bitmap_bit_order = BITMAP_BIT_ORDER;
674 #ifndef INTERNAL_VS_EXTERNAL_PADDING
675 pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->width;
676 pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT;
677 pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD;
678 #else
679 pXWDHeader->pixmap_width = pXWDHeader->window_width = pvfb->paddedWidth;
680 pXWDHeader->bitmap_unit = BITMAP_SCANLINE_UNIT_PROTO;
681 pXWDHeader->bitmap_pad = BITMAP_SCANLINE_PAD_PROTO;
682 #endif
683 pXWDHeader->bits_per_pixel = pvfb->bitsPerPixel;
684 pXWDHeader->bytes_per_line = pvfb->paddedBytesWidth;
685 pXWDHeader->ncolors = pvfb->ncolors;
686
687 /* visual related fields are written when colormap is installed */
688
689 pXWDHeader->window_x = pXWDHeader->window_y = 0;
690 pXWDHeader->window_bdrwidth = 0;
691
692 /* write xwd "window" name: Xvfb hostname:server.screen */
693
694 if (-1 == gethostname(hostname, sizeof(hostname)))
695 hostname[0] = 0;
696 else
697 hostname[XWD_WINDOW_NAME_LEN - 1] = 0;
698 sprintf((char *) (pXWDHeader + 1), "Xvfb %s:%s.%d", hostname, display,
699 pScreen->myNum);
700
701 /* write colormap pixel slot values */
702
703 for (i = 0; i < pvfb->ncolors; i++) {
704 pvfb->pXWDCmap[i].pixel = i;
705 }
706
707 /* byte swap to most significant byte first */
708
709 if (needswap) {
710 SwapLongs((CARD32 *) pXWDHeader, SIZEOF(XWDheader) / 4);
711 for (i = 0; i < pvfb->ncolors; i++) {
712 swapl(&pvfb->pXWDCmap[i].pixel);
713 }
714 }
715 }
716
717 static Bool
vfbCursorOffScreen(ScreenPtr * ppScreen,int * x,int * y)718 vfbCursorOffScreen(ScreenPtr *ppScreen, int *x, int *y)
719 {
720 return FALSE;
721 }
722
723 static void
vfbCrossScreen(ScreenPtr pScreen,Bool entering)724 vfbCrossScreen(ScreenPtr pScreen, Bool entering)
725 {
726 }
727
728 static miPointerScreenFuncRec vfbPointerCursorFuncs = {
729 vfbCursorOffScreen,
730 vfbCrossScreen,
731 miPointerWarpCursor
732 };
733
734 static Bool
vfbCloseScreen(ScreenPtr pScreen)735 vfbCloseScreen(ScreenPtr pScreen)
736 {
737 vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
738
739 pScreen->CloseScreen = pvfb->closeScreen;
740
741 /*
742 * fb overwrites miCloseScreen, so do this here
743 */
744 if (pScreen->devPrivate)
745 (*pScreen->DestroyPixmap) (pScreen->devPrivate);
746 pScreen->devPrivate = NULL;
747
748 return pScreen->CloseScreen(pScreen);
749 }
750
751 static Bool
vfbRROutputValidateMode(ScreenPtr pScreen,RROutputPtr output,RRModePtr mode)752 vfbRROutputValidateMode(ScreenPtr pScreen,
753 RROutputPtr output,
754 RRModePtr mode)
755 {
756 rrScrPriv(pScreen);
757
758 if (pScrPriv->minWidth <= mode->mode.width &&
759 pScrPriv->maxWidth >= mode->mode.width &&
760 pScrPriv->minHeight <= mode->mode.height &&
761 pScrPriv->maxHeight >= mode->mode.height)
762 return TRUE;
763 else
764 return FALSE;
765 }
766
767 static Bool
vfbRRScreenSetSize(ScreenPtr pScreen,CARD16 width,CARD16 height,CARD32 mmWidth,CARD32 mmHeight)768 vfbRRScreenSetSize(ScreenPtr pScreen,
769 CARD16 width,
770 CARD16 height,
771 CARD32 mmWidth,
772 CARD32 mmHeight)
773 {
774 // Prevent screen updates while we change things around
775 SetRootClip(pScreen, ROOT_CLIP_NONE);
776
777 pScreen->width = width;
778 pScreen->height = height;
779 pScreen->mmWidth = mmWidth;
780 pScreen->mmHeight = mmHeight;
781
782 // Restore the ability to update screen, now with new dimensions
783 SetRootClip(pScreen, ROOT_CLIP_FULL);
784
785 RRScreenSizeNotify (pScreen);
786 RRTellChanged(pScreen);
787
788 return TRUE;
789 }
790
791 static Bool
vfbRRCrtcSet(ScreenPtr pScreen,RRCrtcPtr crtc,RRModePtr mode,int x,int y,Rotation rotation,int numOutput,RROutputPtr * outputs)792 vfbRRCrtcSet(ScreenPtr pScreen,
793 RRCrtcPtr crtc,
794 RRModePtr mode,
795 int x,
796 int y,
797 Rotation rotation,
798 int numOutput,
799 RROutputPtr *outputs)
800 {
801 return RRCrtcNotify(crtc, mode, x, y, rotation, NULL, numOutput, outputs);
802 }
803
804 static Bool
vfbRRGetInfo(ScreenPtr pScreen,Rotation * rotations)805 vfbRRGetInfo(ScreenPtr pScreen, Rotation *rotations)
806 {
807 return TRUE;
808 }
809
810 static Bool
vfbRandRInit(ScreenPtr pScreen)811 vfbRandRInit(ScreenPtr pScreen)
812 {
813 rrScrPrivPtr pScrPriv;
814 #if RANDR_12_INTERFACE
815 RRModePtr mode;
816 RRCrtcPtr crtc;
817 RROutputPtr output;
818 xRRModeInfo modeInfo;
819 char name[64];
820 #endif
821
822 if (!RRScreenInit (pScreen))
823 return FALSE;
824 pScrPriv = rrGetScrPriv(pScreen);
825 pScrPriv->rrGetInfo = vfbRRGetInfo;
826 #if RANDR_12_INTERFACE
827 pScrPriv->rrCrtcSet = vfbRRCrtcSet;
828 pScrPriv->rrScreenSetSize = vfbRRScreenSetSize;
829 pScrPriv->rrOutputSetProperty = NULL;
830 #if RANDR_13_INTERFACE
831 pScrPriv->rrOutputGetProperty = NULL;
832 #endif
833 pScrPriv->rrOutputValidateMode = vfbRROutputValidateMode;
834 pScrPriv->rrModeDestroy = NULL;
835
836 RRScreenSetSizeRange (pScreen,
837 1, 1,
838 pScreen->width, pScreen->height);
839
840 sprintf (name, "%dx%d", pScreen->width, pScreen->height);
841 memset (&modeInfo, '\0', sizeof (modeInfo));
842 modeInfo.width = pScreen->width;
843 modeInfo.height = pScreen->height;
844 modeInfo.nameLength = strlen (name);
845
846 mode = RRModeGet (&modeInfo, name);
847 if (!mode)
848 return FALSE;
849
850 crtc = RRCrtcCreate (pScreen, NULL);
851 if (!crtc)
852 return FALSE;
853
854 output = RROutputCreate (pScreen, "screen", 6, NULL);
855 if (!output)
856 return FALSE;
857 if (!RROutputSetClones (output, NULL, 0))
858 return FALSE;
859 if (!RROutputSetModes (output, &mode, 1, 0))
860 return FALSE;
861 if (!RROutputSetCrtcs (output, &crtc, 1))
862 return FALSE;
863 if (!RROutputSetConnection (output, RR_Connected))
864 return FALSE;
865 RRCrtcNotify (crtc, mode, 0, 0, RR_Rotate_0, NULL, 1, &output);
866 #endif
867 return TRUE;
868 }
869
870 static Bool
vfbScreenInit(ScreenPtr pScreen,int argc,char ** argv)871 vfbScreenInit(ScreenPtr pScreen, int argc, char **argv)
872 {
873 vfbScreenInfoPtr pvfb = &vfbScreens[pScreen->myNum];
874 int dpix = monitorResolution, dpiy = monitorResolution;
875 int ret;
876 char *pbits;
877
878 if (dpix == 0)
879 dpix = 100;
880
881 if (dpiy == 0)
882 dpiy = 100;
883
884 pvfb->paddedBytesWidth = PixmapBytePad(pvfb->width, pvfb->depth);
885 pvfb->bitsPerPixel = vfbBitsPerPixel(pvfb->depth);
886 if (pvfb->bitsPerPixel >= 8)
887 pvfb->paddedWidth = pvfb->paddedBytesWidth / (pvfb->bitsPerPixel / 8);
888 else
889 pvfb->paddedWidth = pvfb->paddedBytesWidth * 8;
890 pbits = vfbAllocateFramebufferMemory(pvfb);
891 if (!pbits)
892 return FALSE;
893
894 switch (pvfb->depth) {
895 case 8:
896 miSetVisualTypesAndMasks(8,
897 ((1 << StaticGray) |
898 (1 << GrayScale) |
899 (1 << StaticColor) |
900 (1 << PseudoColor) |
901 (1 << TrueColor) |
902 (1 << DirectColor)), 8, PseudoColor, 0, 0, 0);
903 break;
904 case 15:
905 miSetVisualTypesAndMasks(15,
906 ((1 << TrueColor) |
907 (1 << DirectColor)),
908 8, TrueColor, 0x7c00, 0x03e0, 0x001f);
909 break;
910 case 16:
911 miSetVisualTypesAndMasks(16,
912 ((1 << TrueColor) |
913 (1 << DirectColor)),
914 8, TrueColor, 0xf800, 0x07e0, 0x001f);
915 break;
916 case 24:
917 miSetVisualTypesAndMasks(24,
918 ((1 << TrueColor) |
919 (1 << DirectColor)),
920 8, TrueColor, 0xff0000, 0x00ff00, 0x0000ff);
921 break;
922 case 30:
923 miSetVisualTypesAndMasks(30,
924 ((1 << TrueColor) |
925 (1 << DirectColor)),
926 10, TrueColor, 0x3ff00000, 0x000ffc00,
927 0x000003ff);
928 break;
929 default:
930 return FALSE;
931 }
932
933 miSetPixmapDepths();
934
935 ret = fbScreenInit(pScreen, pbits, pvfb->width, pvfb->height,
936 dpix, dpiy, pvfb->paddedWidth, pvfb->bitsPerPixel);
937 if (ret && Render)
938 fbPictureInit(pScreen, 0, 0);
939
940 if (!ret)
941 return FALSE;
942
943 if (!vfbRandRInit(pScreen))
944 return FALSE;
945
946 pScreen->InstallColormap = vfbInstallColormap;
947
948 pScreen->SaveScreen = vfbSaveScreen;
949 pScreen->StoreColors = vfbStoreColors;
950
951 miDCInitialize(pScreen, &vfbPointerCursorFuncs);
952
953 vfbWriteXWDFileHeader(pScreen);
954
955 pScreen->blackPixel = pvfb->blackPixel;
956 pScreen->whitePixel = pvfb->whitePixel;
957
958 ret = fbCreateDefColormap(pScreen);
959
960 miSetZeroLineBias(pScreen, pvfb->lineBias);
961
962 pvfb->closeScreen = pScreen->CloseScreen;
963 pScreen->CloseScreen = vfbCloseScreen;
964
965 return ret;
966
967 } /* end vfbScreenInit */
968
969 void
InitOutput(ScreenInfo * screen_info,int argc,char ** argv)970 InitOutput(ScreenInfo * screen_info, int argc, char **argv)
971 {
972 int i;
973 int NumFormats = 0;
974
975 /* initialize pixmap formats */
976
977 /* must have a pixmap depth to match every screen depth */
978 for (i = 0; i < vfbNumScreens; i++) {
979 vfbPixmapDepths[vfbScreens[i].depth] = TRUE;
980 }
981
982 /* RENDER needs a good set of pixmaps. */
983 if (Render) {
984 vfbPixmapDepths[1] = TRUE;
985 vfbPixmapDepths[4] = TRUE;
986 vfbPixmapDepths[8] = TRUE;
987 #if 0
988 vfbPixmapDepths[12] = TRUE;
989 #endif
990 /* vfbPixmapDepths[15] = TRUE; */
991 vfbPixmapDepths[16] = TRUE;
992 vfbPixmapDepths[24] = TRUE;
993 #if 0
994 vfbPixmapDepths[30] = TRUE;
995 #endif
996 vfbPixmapDepths[32] = TRUE;
997 }
998
999 xorgGlxCreateVendor();
1000
1001 for (i = 1; i <= 32; i++) {
1002 if (vfbPixmapDepths[i]) {
1003 if (NumFormats >= MAXFORMATS)
1004 FatalError("MAXFORMATS is too small for this server\n");
1005 screen_info->formats[NumFormats].depth = i;
1006 screen_info->formats[NumFormats].bitsPerPixel = vfbBitsPerPixel(i);
1007 screen_info->formats[NumFormats].scanlinePad = BITMAP_SCANLINE_PAD;
1008 NumFormats++;
1009 }
1010 }
1011
1012 screen_info->imageByteOrder = IMAGE_BYTE_ORDER;
1013 screen_info->bitmapScanlineUnit = BITMAP_SCANLINE_UNIT;
1014 screen_info->bitmapScanlinePad = BITMAP_SCANLINE_PAD;
1015 screen_info->bitmapBitOrder = BITMAP_BIT_ORDER;
1016 screen_info->numPixmapFormats = NumFormats;
1017
1018 /* initialize screens */
1019
1020 if (vfbNumScreens < 1) {
1021 vfbScreens = &defaultScreenInfo;
1022 vfbNumScreens = 1;
1023 }
1024 for (i = 0; i < vfbNumScreens; i++) {
1025 if (-1 == AddScreen(vfbScreenInit, argc, argv)) {
1026 FatalError("Couldn't add screen %d", i);
1027 }
1028 }
1029
1030 } /* end InitOutput */
1031