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