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