Squashed commit of the following:
[profile/ivi/mesa.git] / src / gallium / state_trackers / xorg / xorg_driver.c
1 /*
2  * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3  * All Rights Reserved.
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the
7  * "Software"), to deal in the Software without restriction, including
8  * without limitation the rights to use, copy, modify, merge, publish,
9  * distribute, sub license, and/or sell copies of the Software, and to
10  * permit persons to whom the Software is furnished to do so, subject to
11  * the following conditions:
12  *
13  * The above copyright notice and this permission notice (including the
14  * next paragraph) shall be included in all copies or substantial portions
15  * of the Software.
16  *
17  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
18  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
19  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
20  * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
21  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
22  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
23  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
24  *
25  *
26  * Author: Alan Hourihane <alanh@tungstengraphics.com>
27  * Author: Jakob Bornecrantz <wallbraker@gmail.com>
28  *
29  */
30
31
32 #include "xorg-server.h"
33 #include "xf86.h"
34 #include "xf86_OSproc.h"
35 #include "compiler.h"
36 #include "xf86PciInfo.h"
37 #include "xf86Pci.h"
38 #include "mipointer.h"
39 #include "micmap.h"
40 #include <X11/extensions/randr.h>
41 #include "fb.h"
42 #include "edid.h"
43 #include "xf86i2c.h"
44 #include "xf86Crtc.h"
45 #include "miscstruct.h"
46 #include "dixstruct.h"
47 #include "xf86xv.h"
48 #ifndef XSERVER_LIBPCIACCESS
49 #error "libpciaccess needed"
50 #endif
51
52 #include <pciaccess.h>
53
54 #include "pipe/p_context.h"
55 #include "xorg_tracker.h"
56 #include "xorg_winsys.h"
57
58 #ifdef HAVE_LIBKMS
59 #include "libkms.h"
60 #endif
61
62 /*
63  * Functions and symbols exported to Xorg via pointers.
64  */
65
66 static Bool drv_pre_init(ScrnInfoPtr pScrn, int flags);
67 static Bool drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc,
68                             char **argv);
69 static Bool drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags);
70 static void drv_adjust_frame(int scrnIndex, int x, int y, int flags);
71 static Bool drv_enter_vt(int scrnIndex, int flags);
72 static void drv_leave_vt(int scrnIndex, int flags);
73 static void drv_free_screen(int scrnIndex, int flags);
74 static ModeStatus drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose,
75                                  int flags);
76
77 typedef enum
78 {
79     OPTION_SW_CURSOR,
80     OPTION_2D_ACCEL,
81     OPTION_DEBUG_FALLBACK,
82 } drv_option_enums;
83
84 static const OptionInfoRec drv_options[] = {
85     {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
86     {OPTION_2D_ACCEL, "2DAccel", OPTV_BOOLEAN, {0}, FALSE},
87     {OPTION_DEBUG_FALLBACK, "DebugFallback", OPTV_BOOLEAN, {0}, FALSE},
88     {-1, NULL, OPTV_NONE, {0}, FALSE}
89 };
90
91
92 /*
93  * Exported Xorg driver functions to winsys
94  */
95
96 const OptionInfoRec *
97 xorg_tracker_available_options(int chipid, int busid)
98 {
99     return drv_options;
100 }
101
102 void
103 xorg_tracker_set_functions(ScrnInfoPtr scrn)
104 {
105     scrn->PreInit = drv_pre_init;
106     scrn->ScreenInit = drv_screen_init;
107     scrn->SwitchMode = drv_switch_mode;
108     scrn->AdjustFrame = drv_adjust_frame;
109     scrn->EnterVT = drv_enter_vt;
110     scrn->LeaveVT = drv_leave_vt;
111     scrn->FreeScreen = drv_free_screen;
112     scrn->ValidMode = drv_valid_mode;
113 }
114
115 Bool
116 xorg_tracker_have_modesetting(ScrnInfoPtr pScrn, struct pci_device *device)
117 {
118     char *BusID = xalloc(64);
119     sprintf(BusID, "pci:%04x:%02x:%02x.%d",
120             device->domain, device->bus,
121             device->dev, device->func);
122
123     if (drmCheckModesettingSupported(BusID)) {
124         xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
125                        "Drm modesetting not supported %s\n", BusID);
126         xfree(BusID);
127         return FALSE;
128     }
129
130     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
131                    "Drm modesetting supported on %s\n", BusID);
132
133     xfree(BusID);
134     return TRUE;
135 }
136
137
138 /*
139  * Internal function definitions
140  */
141
142 static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn);
143 static Bool drv_close_screen(int scrnIndex, ScreenPtr pScreen);
144 static Bool drv_save_hw_state(ScrnInfoPtr pScrn);
145 static Bool drv_restore_hw_state(ScrnInfoPtr pScrn);
146
147
148 /*
149  * Internal functions
150  */
151
152 static Bool
153 drv_get_rec(ScrnInfoPtr pScrn)
154 {
155     if (pScrn->driverPrivate)
156         return TRUE;
157
158     pScrn->driverPrivate = xnfcalloc(1, sizeof(modesettingRec));
159
160     return TRUE;
161 }
162
163 static void
164 drv_free_rec(ScrnInfoPtr pScrn)
165 {
166     if (!pScrn)
167         return;
168
169     if (!pScrn->driverPrivate)
170         return;
171
172     xfree(pScrn->driverPrivate);
173
174     pScrn->driverPrivate = NULL;
175 }
176
177 static void
178 drv_probe_ddc(ScrnInfoPtr pScrn, int index)
179 {
180     ConfiguredMonitor = NULL;
181 }
182
183 static Bool
184 drv_crtc_resize(ScrnInfoPtr pScrn, int width, int height)
185 {
186     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
187     modesettingPtr ms = modesettingPTR(pScrn);
188     ScreenPtr pScreen = pScrn->pScreen;
189     int old_width, old_height;
190     PixmapPtr rootPixmap;
191     int i;
192
193     if (width == pScrn->virtualX && height == pScrn->virtualY)
194         return TRUE;
195
196     old_width = pScrn->virtualX;
197     old_height = pScrn->virtualY;
198     pScrn->virtualX = width;
199     pScrn->virtualY = height;
200
201     /* ms->create_front_buffer will remove the old front buffer */
202
203     rootPixmap = pScreen->GetScreenPixmap(pScreen);
204     if (!pScreen->ModifyPixmapHeader(rootPixmap, width, height, -1, -1, -1, NULL))
205         goto error_modify;
206
207     pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8);
208
209     if (!ms->create_front_buffer(pScrn) || !ms->bind_front_buffer(pScrn))
210         goto error_create;
211
212     /*
213      * create && bind will turn off all crtc(s) in the kernel so we need to
214      * re-enable all the crtcs again. For real HW we might want to do this
215      * before destroying the old framebuffer.
216      */
217     for (i = 0; i < xf86_config->num_crtc; i++) {
218         xf86CrtcPtr crtc = xf86_config->crtc[i];
219
220         if (!crtc->enabled)
221             continue;
222
223         crtc->funcs->set_mode_major(crtc, &crtc->mode, crtc->rotation, crtc->x, crtc->y);
224     }
225
226     return TRUE;
227
228     /*
229      * This is the error recovery path.
230      */
231 error_create:
232     if (!pScreen->ModifyPixmapHeader(rootPixmap, old_width, old_height, -1, -1, -1, NULL))
233         FatalError("failed to resize rootPixmap error path\n");
234
235     pScrn->displayWidth = rootPixmap->devKind / (rootPixmap->drawable.bitsPerPixel / 8);
236
237 error_modify:
238     pScrn->virtualX = old_width;
239     pScrn->virtualY = old_height;
240
241     if (ms->create_front_buffer(pScrn) && ms->bind_front_buffer(pScrn))
242         return FALSE;
243
244     FatalError("failed to setup old framebuffer\n");
245     return FALSE;
246 }
247
248 static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
249     .resize = drv_crtc_resize
250 };
251
252 static Bool
253 drv_init_drm(ScrnInfoPtr pScrn)
254 {
255     modesettingPtr ms = modesettingPTR(pScrn);
256
257     /* deal with server regeneration */
258     if (ms->fd < 0) {
259         char *BusID;
260
261         BusID = xalloc(64);
262         sprintf(BusID, "PCI:%d:%d:%d",
263                 ((ms->PciInfo->domain << 8) | ms->PciInfo->bus),
264                 ms->PciInfo->dev, ms->PciInfo->func
265             );
266
267
268         ms->api = drm_api_create();
269         ms->fd = drmOpen(ms->api ? ms->api->driver_name : NULL, BusID);
270         xfree(BusID);
271
272         if (ms->fd >= 0)
273             return TRUE;
274
275         if (ms->api && ms->api->destroy)
276             ms->api->destroy(ms->api);
277
278         ms->api = NULL;
279
280         return FALSE;
281     }
282
283     return TRUE;
284 }
285
286 static Bool
287 drv_close_drm(ScrnInfoPtr pScrn)
288 {
289     modesettingPtr ms = modesettingPTR(pScrn);
290
291     if (ms->api && ms->api->destroy)
292         ms->api->destroy(ms->api);
293     ms->api = NULL;
294
295     drmClose(ms->fd);
296     ms->fd = -1;
297
298     return TRUE;
299 }
300
301 static Bool
302 drv_init_resource_management(ScrnInfoPtr pScrn)
303 {
304     modesettingPtr ms = modesettingPTR(pScrn);
305     /*
306     ScreenPtr pScreen = pScrn->pScreen;
307     PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
308     Bool fbAccessDisabled;
309     CARD8 *fbstart;
310      */
311
312     if (ms->screen || ms->kms)
313         return TRUE;
314
315     if (ms->api) {
316         ms->screen = ms->api->create_screen(ms->api, ms->fd, NULL);
317
318         if (ms->screen)
319             return TRUE;
320
321         if (ms->api->destroy)
322             ms->api->destroy(ms->api);
323
324         ms->api = NULL;
325     }
326
327 #ifdef HAVE_LIBKMS
328     if (!kms_create(ms->fd, &ms->kms))
329         return TRUE;
330 #endif
331
332     return FALSE;
333 }
334
335 static Bool
336 drv_close_resource_management(ScrnInfoPtr pScrn)
337 {
338     modesettingPtr ms = modesettingPTR(pScrn);
339     int i;
340
341     if (ms->screen) {
342         assert(ms->ctx == NULL);
343
344         for (i = 0; i < XORG_NR_FENCES; i++) {
345             if (ms->fence[i]) {
346                 ms->screen->fence_finish(ms->screen, ms->fence[i], 0);
347                 ms->screen->fence_reference(ms->screen, &ms->fence[i], NULL);
348             }
349         }
350         ms->screen->destroy(ms->screen);
351     }
352     ms->screen = NULL;
353
354 #ifdef HAVE_LIBKMS
355     if (ms->kms)
356         kms_destroy(&ms->kms);
357 #endif
358
359     return TRUE;
360 }
361
362 static Bool
363 drv_pre_init(ScrnInfoPtr pScrn, int flags)
364 {
365     xf86CrtcConfigPtr xf86_config;
366     modesettingPtr ms;
367     rgb defaultWeight = { 0, 0, 0 };
368     EntityInfoPtr pEnt;
369     EntPtr msEnt = NULL;
370     int max_width, max_height;
371     CustomizerPtr cust;
372
373     if (pScrn->numEntities != 1)
374         return FALSE;
375
376     pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
377
378     if (flags & PROBE_DETECT) {
379         drv_probe_ddc(pScrn, pEnt->index);
380         return TRUE;
381     }
382
383     cust = (CustomizerPtr) pScrn->driverPrivate;
384     pScrn->driverPrivate = NULL;
385
386     /* Allocate driverPrivate */
387     if (!drv_get_rec(pScrn))
388         return FALSE;
389
390     ms = modesettingPTR(pScrn);
391     ms->SaveGeneration = -1;
392     ms->pEnt = pEnt;
393     ms->cust = cust;
394
395     pScrn->displayWidth = 640;         /* default it */
396
397     if (ms->pEnt->location.type != BUS_PCI)
398         return FALSE;
399
400     ms->PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
401
402     /* Allocate an entity private if necessary */
403     if (xf86IsEntityShared(pScrn->entityList[0])) {
404         FatalError("Entity");
405 #if 0
406         msEnt = xf86GetEntityPrivate(pScrn->entityList[0],
407                                      modesettingEntityIndex)->ptr;
408         ms->entityPrivate = msEnt;
409 #else
410         (void)msEnt;
411 #endif
412     } else
413         ms->entityPrivate = NULL;
414
415     if (xf86IsEntityShared(pScrn->entityList[0])) {
416         if (xf86IsPrimInitDone(pScrn->entityList[0])) {
417             /* do something */
418         } else {
419             xf86SetPrimInitDone(pScrn->entityList[0]);
420         }
421     }
422
423     ms->fd = -1;
424     ms->api = NULL;
425     if (!drv_init_drm(pScrn))
426         return FALSE;
427
428     pScrn->monitor = pScrn->confScreen->monitor;
429     pScrn->progClock = TRUE;
430     pScrn->rgbBits = 8;
431
432     if (!xf86SetDepthBpp
433         (pScrn, 0, 0, 0,
434          PreferConvert24to32 | SupportConvert24to32 | Support32bppFb))
435         return FALSE;
436
437     switch (pScrn->depth) {
438     case 15:
439     case 16:
440     case 24:
441         break;
442     default:
443         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
444                    "Given depth (%d) is not supported by the driver\n",
445                    pScrn->depth);
446         return FALSE;
447     }
448     xf86PrintDepthBpp(pScrn);
449
450     if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
451         return FALSE;
452     if (!xf86SetDefaultVisual(pScrn, -1))
453         return FALSE;
454
455     /* Process the options */
456     xf86CollectOptions(pScrn, NULL);
457     if (!(ms->Options = xalloc(sizeof(drv_options))))
458         return FALSE;
459     memcpy(ms->Options, drv_options, sizeof(drv_options));
460     xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->Options);
461
462     /* Allocate an xf86CrtcConfig */
463     xf86CrtcConfigInit(pScrn, &crtc_config_funcs);
464     xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
465
466     max_width = 2048;  /* A very low default */
467     max_height = 2048; /* see screen_init */
468     xf86CrtcSetSizeRange(pScrn, 320, 200, max_width, max_height);
469
470     if (xf86ReturnOptValBool(ms->Options, OPTION_SW_CURSOR, FALSE)) {
471         ms->SWCursor = TRUE;
472     }
473
474     drv_save_hw_state(pScrn);
475
476     xorg_crtc_init(pScrn);
477     xorg_output_init(pScrn);
478
479     if (!xf86InitialConfiguration(pScrn, TRUE)) {
480         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No valid modes.\n");
481         drv_restore_hw_state(pScrn);
482         return FALSE;
483     }
484
485     drv_restore_hw_state(pScrn);
486
487     /*
488      * If the driver can do gamma correction, it should call xf86SetGamma() here.
489      */
490     {
491         Gamma zeros = { 0.0, 0.0, 0.0 };
492
493         if (!xf86SetGamma(pScrn, zeros)) {
494             return FALSE;
495         }
496     }
497
498     if (pScrn->modes == NULL) {
499         xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
500         return FALSE;
501     }
502
503     pScrn->currentMode = pScrn->modes;
504
505     /* Set display resolution */
506     xf86SetDpi(pScrn, 0, 0);
507
508     /* Load the required sub modules */
509     if (!xf86LoadSubModule(pScrn, "fb"))
510         return FALSE;
511
512     /* XXX: these aren't needed when we are using libkms */
513     if (!xf86LoadSubModule(pScrn, "exa"))
514         return FALSE;
515
516 #ifdef DRI2
517     if (!xf86LoadSubModule(pScrn, "dri2"))
518         return FALSE;
519 #endif
520
521     return TRUE;
522 }
523
524 static Bool
525 drv_save_hw_state(ScrnInfoPtr pScrn)
526 {
527     /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
528
529     return TRUE;
530 }
531
532 static Bool
533 drv_restore_hw_state(ScrnInfoPtr pScrn)
534 {
535     /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
536
537     return TRUE;
538 }
539
540 static void drv_block_handler(int i, pointer blockData, pointer pTimeout,
541                               pointer pReadmask)
542 {
543     ScreenPtr pScreen = screenInfo.screens[i];
544     modesettingPtr ms = modesettingPTR(xf86Screens[pScreen->myNum]);
545
546     pScreen->BlockHandler = ms->blockHandler;
547     pScreen->BlockHandler(i, blockData, pTimeout, pReadmask);
548     pScreen->BlockHandler = drv_block_handler;
549
550     if (ms->ctx) {
551        int j;
552
553        ms->ctx->flush(ms->ctx, PIPE_FLUSH_RENDER_CACHE, &ms->fence[XORG_NR_FENCES-1]);
554        
555        if (ms->fence[0])
556           ms->ctx->screen->fence_finish(ms->ctx->screen, ms->fence[0], 0);
557   
558        /* The amount of rendering generated by a block handler can be
559         * quite small.  Let us get a fair way ahead of hardware before
560         * throttling.
561         */
562        for (j = 0; j < XORG_NR_FENCES - 1; j++)
563           ms->screen->fence_reference(ms->screen,
564                                       &ms->fence[j],
565                                       ms->fence[j+1]);
566
567        ms->screen->fence_reference(ms->screen,
568                                    &ms->fence[XORG_NR_FENCES-1],
569                                    NULL);
570     }
571         
572
573 #ifdef DRM_MODE_FEATURE_DIRTYFB
574     {
575         RegionPtr dirty = DamageRegion(ms->damage);
576         unsigned num_cliprects = REGION_NUM_RECTS(dirty);
577
578         if (num_cliprects) {
579             drmModeClip *clip = alloca(num_cliprects * sizeof(drmModeClip));
580             BoxPtr rect = REGION_RECTS(dirty);
581             int i, ret;
582
583             /* XXX no need for copy? */
584             for (i = 0; i < num_cliprects; i++, rect++) {
585                 clip[i].x1 = rect->x1;
586                 clip[i].y1 = rect->y1;
587                 clip[i].x2 = rect->x2;
588                 clip[i].y2 = rect->y2;
589             }
590
591             /* TODO query connector property to see if this is needed */
592             ret = drmModeDirtyFB(ms->fd, ms->fb_id, clip, num_cliprects);
593             if (ret) {
594                 debug_printf("%s: failed to send dirty (%i, %s)\n",
595                              __func__, ret, strerror(-ret));
596             }
597
598             DamageEmpty(ms->damage);
599         }
600     }
601 #endif
602 }
603
604 static Bool
605 drv_create_screen_resources(ScreenPtr pScreen)
606 {
607     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
608     modesettingPtr ms = modesettingPTR(pScrn);
609     PixmapPtr rootPixmap;
610     Bool ret;
611
612     ms->noEvict = TRUE;
613
614     pScreen->CreateScreenResources = ms->createScreenResources;
615     ret = pScreen->CreateScreenResources(pScreen);
616     pScreen->CreateScreenResources = drv_create_screen_resources;
617
618     ms->bind_front_buffer(pScrn);
619
620     ms->noEvict = FALSE;
621
622     drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
623
624 #ifdef DRM_MODE_FEATURE_DIRTYFB
625     rootPixmap = pScreen->GetScreenPixmap(pScreen);
626     ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
627                               pScreen, rootPixmap);
628
629     if (ms->damage) {
630        DamageRegister(&rootPixmap->drawable, ms->damage);
631
632        xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
633     } else {
634        xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
635                   "Failed to create screen damage record\n");
636        return FALSE;
637     }
638 #else
639     (void)rootPixmap;
640 #endif
641
642     return ret;
643 }
644
645 static Bool
646 drv_screen_init(int scrnIndex, ScreenPtr pScreen, int argc, char **argv)
647 {
648     ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
649     modesettingPtr ms = modesettingPTR(pScrn);
650     unsigned max_width, max_height;
651     VisualPtr visual;
652     CustomizerPtr cust = ms->cust;
653
654     if (!drv_init_drm(pScrn)) {
655         FatalError("Could not init DRM");
656         return FALSE;
657     }
658
659     if (!drv_init_resource_management(pScrn)) {
660         FatalError("Could not init resource management (!pipe_screen && !libkms)");
661         return FALSE;
662     }
663
664     if (!drv_init_front_buffer_functions(pScrn)) {
665         FatalError("Could not init front buffer manager");
666         return FALSE;
667     }
668
669     /* get max width and height */
670     {
671         drmModeResPtr res;
672         res = drmModeGetResources(ms->fd);
673         max_width = res->max_width;
674         max_height = res->max_height;
675         drmModeFreeResources(res);
676     }
677
678     if (ms->screen) {
679         int max;
680         max = ms->screen->get_param(ms->screen, PIPE_CAP_MAX_TEXTURE_2D_LEVELS);
681         max = 1 << (max - 1);
682         max_width = max < max_width ? max : max_width;
683         max_height = max < max_height ? max : max_height;
684     }
685
686     xf86CrtcSetSizeRange(pScrn, 1, 1, max_width, max_height);
687
688     pScrn->pScreen = pScreen;
689
690     /* HW dependent - FIXME */
691     pScrn->displayWidth = pScrn->virtualX;
692
693     miClearVisualTypes();
694
695     if (!miSetVisualTypes(pScrn->depth,
696                           miGetDefaultVisualMask(pScrn->depth),
697                           pScrn->rgbBits, pScrn->defaultVisual))
698         return FALSE;
699
700     if (!miSetPixmapDepths())
701         return FALSE;
702
703     pScrn->memPhysBase = 0;
704     pScrn->fbOffset = 0;
705
706     if (!fbScreenInit(pScreen, NULL,
707                       pScrn->virtualX, pScrn->virtualY,
708                       pScrn->xDpi, pScrn->yDpi,
709                       pScrn->displayWidth, pScrn->bitsPerPixel))
710         return FALSE;
711
712     if (pScrn->bitsPerPixel > 8) {
713         /* Fixup RGB ordering */
714         visual = pScreen->visuals + pScreen->numVisuals;
715         while (--visual >= pScreen->visuals) {
716             if ((visual->class | DynamicClass) == DirectColor) {
717                 visual->offsetRed = pScrn->offset.red;
718                 visual->offsetGreen = pScrn->offset.green;
719                 visual->offsetBlue = pScrn->offset.blue;
720                 visual->redMask = pScrn->mask.red;
721                 visual->greenMask = pScrn->mask.green;
722                 visual->blueMask = pScrn->mask.blue;
723             }
724         }
725     }
726
727     fbPictureInit(pScreen, NULL, 0);
728
729     ms->blockHandler = pScreen->BlockHandler;
730     pScreen->BlockHandler = drv_block_handler;
731     ms->createScreenResources = pScreen->CreateScreenResources;
732     pScreen->CreateScreenResources = drv_create_screen_resources;
733
734     xf86SetBlackWhitePixels(pScreen);
735
736     ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE);
737     ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d);
738
739     if (ms->screen) {
740         ms->exa = xorg_exa_init(pScrn, ms->accelerate_2d);
741
742         xorg_xv_init(pScreen);
743 #ifdef DRI2
744         xorg_dri2_init(pScreen);
745 #endif
746     }
747
748     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
749     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Usefull debugging info follows #\n");
750     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
751     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %s backend\n",
752                ms->screen ? "Gallium3D" : "libkms");
753     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s\n",
754                ms->screen && ms->accelerate_2d ? "enabled" : "disabled");
755     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s\n",
756                ms->debug_fallback ? "enabled" : "disabled");
757 #ifdef DRI2
758     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is %s\n",
759                ms->screen ? "enabled" : "disabled");
760 #else
761     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled\n");
762 #endif
763     xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
764
765     miInitializeBackingStore(pScreen);
766     xf86SetBackingStore(pScreen);
767     xf86SetSilkenMouse(pScreen);
768     miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
769
770     /* Need to extend HWcursor support to handle mask interleave */
771     if (!ms->SWCursor)
772         xf86_cursors_init(pScreen, 64, 64,
773                           HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
774                           HARDWARE_CURSOR_ARGB);
775
776     /* Must force it before EnterVT, so we are in control of VT and
777      * later memory should be bound when allocating, e.g rotate_mem */
778     pScrn->vtSema = TRUE;
779
780     pScreen->SaveScreen = xf86SaveScreen;
781     ms->CloseScreen = pScreen->CloseScreen;
782     pScreen->CloseScreen = drv_close_screen;
783
784     if (!xf86CrtcScreenInit(pScreen))
785         return FALSE;
786
787     if (!miCreateDefColormap(pScreen))
788         return FALSE;
789
790     xf86DPMSInit(pScreen, xf86DPMSSet, 0);
791
792     if (serverGeneration == 1)
793         xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
794
795     if (cust && cust->winsys_screen_init)
796         cust->winsys_screen_init(cust, ms->fd);
797
798     return drv_enter_vt(scrnIndex, 1);
799 }
800
801 static void
802 drv_adjust_frame(int scrnIndex, int x, int y, int flags)
803 {
804     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
805     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
806     xf86OutputPtr output = config->output[config->compat_output];
807     xf86CrtcPtr crtc = output->crtc;
808
809     if (crtc && crtc->enabled) {
810         crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
811                                     RR_Rotate_0, x, y);
812         crtc->x = output->initial_x + x;
813         crtc->y = output->initial_y + y;
814     }
815 }
816
817 static void
818 drv_free_screen(int scrnIndex, int flags)
819 {
820     drv_free_rec(xf86Screens[scrnIndex]);
821 }
822
823 static void
824 drv_leave_vt(int scrnIndex, int flags)
825 {
826     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
827     modesettingPtr ms = modesettingPTR(pScrn);
828     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
829     CustomizerPtr cust = ms->cust;
830     int o;
831
832     if (cust && cust->winsys_leave_vt)
833         cust->winsys_leave_vt(cust);
834
835     for (o = 0; o < config->num_crtc; o++) {
836         xf86CrtcPtr crtc = config->crtc[o];
837
838         xorg_crtc_cursor_destroy(crtc);
839
840         if (crtc->rotatedPixmap || crtc->rotatedData) {
841             crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
842                                         crtc->rotatedData);
843             crtc->rotatedPixmap = NULL;
844             crtc->rotatedData = NULL;
845         }
846     }
847
848     drmModeRmFB(ms->fd, ms->fb_id);
849     ms->fb_id = -1;
850
851     drv_restore_hw_state(pScrn);
852
853     if (drmDropMaster(ms->fd))
854         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
855                    "drmDropMaster failed: %s\n", strerror(errno));
856
857     pScrn->vtSema = FALSE;
858 }
859
860 /*
861  * This gets called when gaining control of the VT, and from ScreenInit().
862  */
863 static Bool
864 drv_enter_vt(int scrnIndex, int flags)
865 {
866     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
867     modesettingPtr ms = modesettingPTR(pScrn);
868     CustomizerPtr cust = ms->cust;
869
870     if (drmSetMaster(ms->fd)) {
871         if (errno == EINVAL) {
872             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
873                        "drmSetMaster failed: 2.6.29 or newer kernel required for "
874                        "multi-server DRI\n");
875         } else {
876             xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
877                        "drmSetMaster failed: %s\n", strerror(errno));
878         }
879     }
880
881     /*
882      * Only save state once per server generation since that's what most
883      * drivers do.  Could change this to save state at each VT enter.
884      */
885     if (ms->SaveGeneration != serverGeneration) {
886         ms->SaveGeneration = serverGeneration;
887         drv_save_hw_state(pScrn);
888     }
889
890     if (!ms->create_front_buffer(pScrn))
891         return FALSE;
892
893     if (!flags && !ms->bind_front_buffer(pScrn))
894         return FALSE;
895
896     if (!xf86SetDesiredModes(pScrn))
897         return FALSE;
898
899     if (cust && cust->winsys_enter_vt)
900         cust->winsys_enter_vt(cust);
901
902     return TRUE;
903 }
904
905 static Bool
906 drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
907 {
908     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
909
910     return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
911 }
912
913 static Bool
914 drv_close_screen(int scrnIndex, ScreenPtr pScreen)
915 {
916     ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
917     modesettingPtr ms = modesettingPTR(pScrn);
918     CustomizerPtr cust = ms->cust;
919
920     if (pScrn->vtSema) {
921         drv_leave_vt(scrnIndex, 0);
922     }
923
924     if (ms->cursor) {
925        FreeCursor(ms->cursor, None);
926        ms->cursor = NULL;
927     }
928
929     if (cust && cust->winsys_screen_close)
930         cust->winsys_screen_close(cust);
931
932 #ifdef DRI2
933     if (ms->screen)
934         xorg_dri2_close(pScreen);
935 #endif
936
937     pScreen->BlockHandler = ms->blockHandler;
938     pScreen->CreateScreenResources = ms->createScreenResources;
939
940 #ifdef DRM_MODE_FEATURE_DIRTYFB
941     if (ms->damage) {
942         DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
943         DamageDestroy(ms->damage);
944         ms->damage = NULL;
945     }
946 #endif
947
948     drmModeRmFB(ms->fd, ms->fb_id);
949     ms->destroy_front_buffer(pScrn);
950
951     if (ms->exa)
952         xorg_exa_close(pScrn);
953     ms->exa = NULL;
954
955     drv_close_resource_management(pScrn);
956
957     drv_close_drm(pScrn);
958
959     pScrn->vtSema = FALSE;
960     pScreen->CloseScreen = ms->CloseScreen;
961     return (*pScreen->CloseScreen) (scrnIndex, pScreen);
962 }
963
964 static ModeStatus
965 drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
966 {
967     return MODE_OK;
968 }
969
970
971 /*
972  * Front buffer backing store functions.
973  */
974
975 static Bool
976 drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn)
977 {
978     modesettingPtr ms = modesettingPTR(pScrn);
979
980     if (!ms->root_texture)
981         return TRUE;
982
983     if (ms->fb_id != -1) {
984         drmModeRmFB(ms->fd, ms->fb_id);
985         ms->fb_id = -1;
986     }
987
988     pipe_resource_reference(&ms->root_texture, NULL);
989     return TRUE;
990 }
991
992 static Bool
993 drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn)
994 {
995     modesettingPtr ms = modesettingPTR(pScrn);
996     struct pipe_resource *tex;
997     struct winsys_handle whandle;
998     unsigned fb_id;
999     int ret;
1000
1001     ms->noEvict = TRUE;
1002
1003     tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY,
1004                                        pScrn->depth, pScrn->bitsPerPixel);
1005
1006     if (!tex)
1007         return FALSE;
1008
1009     memset(&whandle, 0, sizeof(whandle));
1010     whandle.type = DRM_API_HANDLE_TYPE_KMS;
1011
1012     if (!ms->screen->resource_get_handle(ms->screen, tex, &whandle))
1013         goto err_destroy;
1014
1015     ret = drmModeAddFB(ms->fd,
1016                        pScrn->virtualX,
1017                        pScrn->virtualY,
1018                        pScrn->depth,
1019                        pScrn->bitsPerPixel,
1020                        whandle.stride,
1021                        whandle.handle,
1022                        &fb_id);
1023     if (ret) {
1024         debug_printf("%s: failed to create framebuffer (%i, %s)\n",
1025                      __func__, ret, strerror(-ret));
1026         goto err_destroy;
1027     }
1028
1029     if (!drv_destroy_front_buffer_ga3d(pScrn))
1030         FatalError("%s: failed to take down old framebuffer\n", __func__);
1031
1032     pScrn->frameX0 = 0;
1033     pScrn->frameY0 = 0;
1034     drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1035
1036     pipe_resource_reference(&ms->root_texture, tex);
1037     pipe_resource_reference(&tex, NULL);
1038     ms->fb_id = fb_id;
1039
1040     return TRUE;
1041
1042 err_destroy:
1043     pipe_resource_reference(&tex, NULL);
1044     return FALSE;
1045 }
1046
1047 static Bool
1048 drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn)
1049 {
1050     modesettingPtr ms = modesettingPTR(pScrn);
1051     ScreenPtr pScreen = pScrn->pScreen;
1052     PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1053     struct pipe_resource *check;
1054
1055     xorg_exa_set_displayed_usage(rootPixmap);
1056     xorg_exa_set_shared_usage(rootPixmap);
1057     xorg_exa_set_texture(rootPixmap, ms->root_texture);
1058     if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
1059         FatalError("Couldn't adjust screen pixmap\n");
1060
1061     check = xorg_exa_get_texture(rootPixmap);
1062     if (ms->root_texture != check)
1063         FatalError("Created new root texture\n");
1064
1065     pipe_resource_reference(&check, NULL);
1066     return TRUE;
1067 }
1068
1069 #ifdef HAVE_LIBKMS
1070 static Bool
1071 drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn)
1072 {
1073     modesettingPtr ms = modesettingPTR(pScrn);
1074     ScreenPtr pScreen = pScrn->pScreen;
1075     PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1076
1077     /* XXX Do something with the rootPixmap.
1078      * This currently works fine but if we are getting crashes in
1079      * the fb functions after VT switches maybe look more into it.
1080      */
1081     (void)rootPixmap;
1082
1083     if (!ms->root_bo)
1084         return TRUE;
1085
1086     if (ms->fb_id != -1) {
1087         drmModeRmFB(ms->fd, ms->fb_id);
1088         ms->fb_id = -1;
1089     }
1090
1091     kms_bo_unmap(ms->root_bo);
1092     kms_bo_destroy(&ms->root_bo);
1093     return TRUE;
1094 }
1095
1096 static Bool
1097 drv_create_front_buffer_kms(ScrnInfoPtr pScrn)
1098 {
1099     modesettingPtr ms = modesettingPTR(pScrn);
1100     unsigned handle, stride;
1101     struct kms_bo *bo;
1102     unsigned attr[8];
1103     unsigned fb_id;
1104     int ret;
1105
1106     attr[0] = KMS_BO_TYPE;
1107 #ifdef KMS_BO_TYPE_SCANOUT_X8R8G8B8
1108     attr[1] = KMS_BO_TYPE_SCANOUT_X8R8G8B8;
1109 #else
1110     attr[1] = KMS_BO_TYPE_SCANOUT;
1111 #endif
1112     attr[2] = KMS_WIDTH;
1113     attr[3] = pScrn->virtualX;
1114     attr[4] = KMS_HEIGHT;
1115     attr[5] = pScrn->virtualY;
1116     attr[6] = 0;
1117
1118     if (kms_bo_create(ms->kms, attr, &bo))
1119         return FALSE;
1120
1121     if (kms_bo_get_prop(bo, KMS_PITCH, &stride))
1122         goto err_destroy;
1123
1124     if (kms_bo_get_prop(bo, KMS_HANDLE, &handle))
1125         goto err_destroy;
1126
1127     ret = drmModeAddFB(ms->fd,
1128                        pScrn->virtualX,
1129                        pScrn->virtualY,
1130                        pScrn->depth,
1131                        pScrn->bitsPerPixel,
1132                        stride,
1133                        handle,
1134                        &fb_id);
1135     if (ret) {
1136         debug_printf("%s: failed to create framebuffer (%i, %s)",
1137                      __func__, ret, strerror(-ret));
1138         goto err_destroy;
1139     }
1140
1141     if (!drv_destroy_front_buffer_kms(pScrn))
1142         FatalError("%s: could not takedown old bo", __func__);
1143
1144     pScrn->frameX0 = 0;
1145     pScrn->frameY0 = 0;
1146     drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1147     ms->root_bo = bo;
1148     ms->fb_id = fb_id;
1149
1150     return TRUE;
1151
1152 err_destroy:
1153     kms_bo_destroy(&bo);
1154     return FALSE;
1155 }
1156
1157 static Bool
1158 drv_bind_front_buffer_kms(ScrnInfoPtr pScrn)
1159 {
1160     modesettingPtr ms = modesettingPTR(pScrn);
1161     ScreenPtr pScreen = pScrn->pScreen;
1162     PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1163     unsigned stride;
1164     void *ptr;
1165
1166     if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride))
1167         return FALSE;
1168
1169     if (kms_bo_map(ms->root_bo, &ptr))
1170         goto err_destroy;
1171
1172     pScreen->ModifyPixmapHeader(rootPixmap,
1173                                 pScrn->virtualX,
1174                                 pScrn->virtualY,
1175                                 pScreen->rootDepth,
1176                                 pScrn->bitsPerPixel,
1177                                 stride,
1178                                 ptr);
1179
1180     /* This a hack to work around EnableDisableFBAccess setting the pointer
1181      * the real fix would be to replace pScrn->EnableDisableFBAccess hook
1182      * and set the rootPixmap->devPrivate.ptr to something valid before that.
1183      *
1184      * But in its infinit visdome something uses either this some times before
1185      * that, so our hook doesn't get called before the crash happens.
1186      */
1187     pScrn->pixmapPrivate.ptr = ptr;
1188
1189     return TRUE;
1190
1191 err_destroy:
1192     kms_bo_destroy(&ms->root_bo);
1193     return FALSE;
1194 }
1195 #endif /* HAVE_LIBKMS */
1196
1197 static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn)
1198 {
1199     modesettingPtr ms = modesettingPTR(pScrn);
1200     if (ms->screen) {
1201         ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d;
1202         ms->create_front_buffer = drv_create_front_buffer_ga3d;
1203         ms->bind_front_buffer = drv_bind_front_buffer_ga3d;
1204 #ifdef HAVE_LIBKMS
1205     } else if (ms->kms) {
1206         ms->destroy_front_buffer = drv_destroy_front_buffer_kms;
1207         ms->create_front_buffer = drv_create_front_buffer_kms;
1208         ms->bind_front_buffer = drv_bind_front_buffer_kms;
1209 #endif
1210     } else
1211         return FALSE;
1212
1213     return TRUE;
1214 }
1215
1216 CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn)
1217 {
1218     return modesettingPTR(pScrn)->cust;
1219 }
1220
1221 Bool xorg_has_gallium(ScrnInfoPtr pScrn)
1222 {
1223     return modesettingPTR(pScrn)->screen != NULL;
1224 }
1225
1226 /* vim: set sw=4 ts=8 sts=4: */