xorg_driver.c revision 8ddb4e2c81c88c9320ed7fb75464e0b37f4d4536
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);
144static Bool drv_save_hw_state(ScrnInfoPtr pScrn);
145static Bool drv_restore_hw_state(ScrnInfoPtr pScrn);
146
147
148/*
149 * Internal functions
150 */
151
152static Bool
153drv_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
163static void
164drv_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
177static void
178drv_probe_ddc(ScrnInfoPtr pScrn, int index)
179{
180    ConfiguredMonitor = NULL;
181}
182
183static Bool
184drv_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     */
231error_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
237error_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
248static const xf86CrtcConfigFuncsRec crtc_config_funcs = {
249    .resize = drv_crtc_resize
250};
251
252static Bool
253drv_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
286static Bool
287drv_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
301static Bool
302drv_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
335static Bool
336drv_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
362static Bool
363drv_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
524static Bool
525drv_save_hw_state(ScrnInfoPtr pScrn)
526{
527    /*xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);*/
528
529    return TRUE;
530}
531
532static Bool
533drv_restore_hw_state(ScrnInfoPtr pScrn)
534{
535    /*xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);*/
536
537    return TRUE;
538}
539
540static 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
604static Bool
605drv_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
645static Bool
646drv_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_width = max < max_width ? max : max_width;
682	max_height = max < max_height ? max : max_height;
683    }
684
685    xf86CrtcSetSizeRange(pScrn, 1, 1, max_width, max_height);
686
687    pScrn->pScreen = pScreen;
688
689    /* HW dependent - FIXME */
690    pScrn->displayWidth = pScrn->virtualX;
691
692    miClearVisualTypes();
693
694    if (!miSetVisualTypes(pScrn->depth,
695			  miGetDefaultVisualMask(pScrn->depth),
696			  pScrn->rgbBits, pScrn->defaultVisual))
697	return FALSE;
698
699    if (!miSetPixmapDepths())
700	return FALSE;
701
702    pScrn->memPhysBase = 0;
703    pScrn->fbOffset = 0;
704
705    if (!fbScreenInit(pScreen, NULL,
706		      pScrn->virtualX, pScrn->virtualY,
707		      pScrn->xDpi, pScrn->yDpi,
708		      pScrn->displayWidth, pScrn->bitsPerPixel))
709	return FALSE;
710
711    if (pScrn->bitsPerPixel > 8) {
712	/* Fixup RGB ordering */
713	visual = pScreen->visuals + pScreen->numVisuals;
714	while (--visual >= pScreen->visuals) {
715	    if ((visual->class | DynamicClass) == DirectColor) {
716		visual->offsetRed = pScrn->offset.red;
717		visual->offsetGreen = pScrn->offset.green;
718		visual->offsetBlue = pScrn->offset.blue;
719		visual->redMask = pScrn->mask.red;
720		visual->greenMask = pScrn->mask.green;
721		visual->blueMask = pScrn->mask.blue;
722	    }
723	}
724    }
725
726    fbPictureInit(pScreen, NULL, 0);
727
728    ms->blockHandler = pScreen->BlockHandler;
729    pScreen->BlockHandler = drv_block_handler;
730    ms->createScreenResources = pScreen->CreateScreenResources;
731    pScreen->CreateScreenResources = drv_create_screen_resources;
732
733    xf86SetBlackWhitePixels(pScreen);
734
735    ms->accelerate_2d = xf86ReturnOptValBool(ms->Options, OPTION_2D_ACCEL, FALSE);
736    ms->debug_fallback = xf86ReturnOptValBool(ms->Options, OPTION_DEBUG_FALLBACK, ms->accelerate_2d);
737
738    if (ms->screen) {
739	ms->exa = xorg_exa_init(pScrn, ms->accelerate_2d);
740
741	xorg_xv_init(pScreen);
742#ifdef DRI2
743	xorg_dri2_init(pScreen);
744#endif
745    }
746
747    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
748    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "# Usefull debugging info follows #\n");
749    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
750    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Using %s backend\n",
751	       ms->screen ? "Gallium3D" : "libkms");
752    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "2D Acceleration is %s\n",
753	       ms->screen && ms->accelerate_2d ? "enabled" : "disabled");
754    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Fallback debugging is %s\n",
755	       ms->debug_fallback ? "enabled" : "disabled");
756#ifdef DRI2
757    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is %s\n",
758	       ms->screen ? "enabled" : "disabled");
759#else
760    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "3D Acceleration is disabled\n");
761#endif
762    xf86DrvMsg(pScrn->scrnIndex, X_INFO, "##################################\n");
763
764    miInitializeBackingStore(pScreen);
765    xf86SetBackingStore(pScreen);
766    xf86SetSilkenMouse(pScreen);
767    miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
768
769    /* Need to extend HWcursor support to handle mask interleave */
770    if (!ms->SWCursor)
771	xf86_cursors_init(pScreen, 64, 64,
772			  HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
773			  HARDWARE_CURSOR_ARGB);
774
775    /* Must force it before EnterVT, so we are in control of VT and
776     * later memory should be bound when allocating, e.g rotate_mem */
777    pScrn->vtSema = TRUE;
778
779    pScreen->SaveScreen = xf86SaveScreen;
780    ms->CloseScreen = pScreen->CloseScreen;
781    pScreen->CloseScreen = drv_close_screen;
782
783    if (!xf86CrtcScreenInit(pScreen))
784	return FALSE;
785
786    if (!miCreateDefColormap(pScreen))
787	return FALSE;
788
789    xf86DPMSInit(pScreen, xf86DPMSSet, 0);
790
791    if (serverGeneration == 1)
792	xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
793
794    if (cust && cust->winsys_screen_init)
795	cust->winsys_screen_init(cust, ms->fd);
796
797    return drv_enter_vt(scrnIndex, 1);
798}
799
800static void
801drv_adjust_frame(int scrnIndex, int x, int y, int flags)
802{
803    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
804    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
805    xf86OutputPtr output = config->output[config->compat_output];
806    xf86CrtcPtr crtc = output->crtc;
807
808    if (crtc && crtc->enabled) {
809	crtc->funcs->set_mode_major(crtc, pScrn->currentMode,
810				    RR_Rotate_0, x, y);
811	crtc->x = output->initial_x + x;
812	crtc->y = output->initial_y + y;
813    }
814}
815
816static void
817drv_free_screen(int scrnIndex, int flags)
818{
819    drv_free_rec(xf86Screens[scrnIndex]);
820}
821
822static void
823drv_leave_vt(int scrnIndex, int flags)
824{
825    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
826    modesettingPtr ms = modesettingPTR(pScrn);
827    xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
828    CustomizerPtr cust = ms->cust;
829    int o;
830
831    if (cust && cust->winsys_leave_vt)
832	cust->winsys_leave_vt(cust);
833
834    for (o = 0; o < config->num_crtc; o++) {
835	xf86CrtcPtr crtc = config->crtc[o];
836
837	xorg_crtc_cursor_destroy(crtc);
838
839	if (crtc->rotatedPixmap || crtc->rotatedData) {
840	    crtc->funcs->shadow_destroy(crtc, crtc->rotatedPixmap,
841					crtc->rotatedData);
842	    crtc->rotatedPixmap = NULL;
843	    crtc->rotatedData = NULL;
844	}
845    }
846
847    drmModeRmFB(ms->fd, ms->fb_id);
848    ms->fb_id = -1;
849
850    drv_restore_hw_state(pScrn);
851
852    if (drmDropMaster(ms->fd))
853	xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
854		   "drmDropMaster failed: %s\n", strerror(errno));
855
856    pScrn->vtSema = FALSE;
857}
858
859/*
860 * This gets called when gaining control of the VT, and from ScreenInit().
861 */
862static Bool
863drv_enter_vt(int scrnIndex, int flags)
864{
865    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
866    modesettingPtr ms = modesettingPTR(pScrn);
867    CustomizerPtr cust = ms->cust;
868
869    if (drmSetMaster(ms->fd)) {
870	if (errno == EINVAL) {
871	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
872		       "drmSetMaster failed: 2.6.29 or newer kernel required for "
873		       "multi-server DRI\n");
874	} else {
875	    xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
876		       "drmSetMaster failed: %s\n", strerror(errno));
877	}
878    }
879
880    /*
881     * Only save state once per server generation since that's what most
882     * drivers do.  Could change this to save state at each VT enter.
883     */
884    if (ms->SaveGeneration != serverGeneration) {
885	ms->SaveGeneration = serverGeneration;
886	drv_save_hw_state(pScrn);
887    }
888
889    if (!ms->create_front_buffer(pScrn))
890	return FALSE;
891
892    if (!flags && !ms->bind_front_buffer(pScrn))
893	return FALSE;
894
895    if (!xf86SetDesiredModes(pScrn))
896	return FALSE;
897
898    if (cust && cust->winsys_enter_vt)
899	cust->winsys_enter_vt(cust);
900
901    return TRUE;
902}
903
904static Bool
905drv_switch_mode(int scrnIndex, DisplayModePtr mode, int flags)
906{
907    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
908
909    return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
910}
911
912static Bool
913drv_close_screen(int scrnIndex, ScreenPtr pScreen)
914{
915    ScrnInfoPtr pScrn = xf86Screens[scrnIndex];
916    modesettingPtr ms = modesettingPTR(pScrn);
917    CustomizerPtr cust = ms->cust;
918
919    if (pScrn->vtSema) {
920	drv_leave_vt(scrnIndex, 0);
921    }
922
923    if (ms->cursor) {
924       FreeCursor(ms->cursor, None);
925       ms->cursor = NULL;
926    }
927
928    if (cust && cust->winsys_screen_close)
929	cust->winsys_screen_close(cust);
930
931#ifdef DRI2
932    if (ms->screen)
933	xorg_dri2_close(pScreen);
934#endif
935
936    pScreen->BlockHandler = ms->blockHandler;
937    pScreen->CreateScreenResources = ms->createScreenResources;
938
939#ifdef DRM_MODE_FEATURE_DIRTYFB
940    if (ms->damage) {
941	DamageUnregister(&pScreen->GetScreenPixmap(pScreen)->drawable, ms->damage);
942	DamageDestroy(ms->damage);
943	ms->damage = NULL;
944    }
945#endif
946
947    drmModeRmFB(ms->fd, ms->fb_id);
948    ms->destroy_front_buffer(pScrn);
949
950    if (ms->exa)
951	xorg_exa_close(pScrn);
952    ms->exa = NULL;
953
954    drv_close_resource_management(pScrn);
955
956    drv_close_drm(pScrn);
957
958    pScrn->vtSema = FALSE;
959    pScreen->CloseScreen = ms->CloseScreen;
960    return (*pScreen->CloseScreen) (scrnIndex, pScreen);
961}
962
963static ModeStatus
964drv_valid_mode(int scrnIndex, DisplayModePtr mode, Bool verbose, int flags)
965{
966    return MODE_OK;
967}
968
969
970/*
971 * Front buffer backing store functions.
972 */
973
974static Bool
975drv_destroy_front_buffer_ga3d(ScrnInfoPtr pScrn)
976{
977    modesettingPtr ms = modesettingPTR(pScrn);
978
979    if (!ms->root_texture)
980	return TRUE;
981
982    if (ms->fb_id != -1) {
983	drmModeRmFB(ms->fd, ms->fb_id);
984	ms->fb_id = -1;
985    }
986
987    pipe_texture_reference(&ms->root_texture, NULL);
988    return TRUE;
989}
990
991static Bool
992drv_create_front_buffer_ga3d(ScrnInfoPtr pScrn)
993{
994    modesettingPtr ms = modesettingPTR(pScrn);
995    struct pipe_texture *tex;
996    struct winsys_handle whandle;
997    unsigned fb_id;
998    int ret;
999
1000    ms->noEvict = TRUE;
1001
1002    tex = xorg_exa_create_root_texture(pScrn, pScrn->virtualX, pScrn->virtualY,
1003				       pScrn->depth, pScrn->bitsPerPixel);
1004
1005    if (!tex)
1006	return FALSE;
1007
1008    memset(&whandle, 0, sizeof(whandle));
1009    whandle.type = DRM_API_HANDLE_TYPE_KMS;
1010
1011    if (!ms->screen->texture_get_handle(ms->screen, tex, &whandle))
1012	goto err_destroy;
1013
1014    ret = drmModeAddFB(ms->fd,
1015		       pScrn->virtualX,
1016		       pScrn->virtualY,
1017		       pScrn->depth,
1018		       pScrn->bitsPerPixel,
1019		       whandle.stride,
1020		       whandle.handle,
1021		       &fb_id);
1022    if (ret) {
1023	debug_printf("%s: failed to create framebuffer (%i, %s)\n",
1024		     __func__, ret, strerror(-ret));
1025	goto err_destroy;
1026    }
1027
1028    if (!drv_destroy_front_buffer_ga3d(pScrn))
1029	FatalError("%s: failed to take down old framebuffer\n", __func__);
1030
1031    pScrn->frameX0 = 0;
1032    pScrn->frameY0 = 0;
1033    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1034
1035    pipe_texture_reference(&ms->root_texture, tex);
1036    pipe_texture_reference(&tex, NULL);
1037    ms->fb_id = fb_id;
1038
1039    return TRUE;
1040
1041err_destroy:
1042    pipe_texture_reference(&tex, NULL);
1043    return FALSE;
1044}
1045
1046static Bool
1047drv_bind_front_buffer_ga3d(ScrnInfoPtr pScrn)
1048{
1049    modesettingPtr ms = modesettingPTR(pScrn);
1050    ScreenPtr pScreen = pScrn->pScreen;
1051    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1052    struct pipe_texture *check;
1053
1054    xorg_exa_set_displayed_usage(rootPixmap);
1055    xorg_exa_set_shared_usage(rootPixmap);
1056    xorg_exa_set_texture(rootPixmap, ms->root_texture);
1057    if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, NULL))
1058	FatalError("Couldn't adjust screen pixmap\n");
1059
1060    check = xorg_exa_get_texture(rootPixmap);
1061    if (ms->root_texture != check)
1062	FatalError("Created new root texture\n");
1063
1064    pipe_texture_reference(&check, NULL);
1065    return TRUE;
1066}
1067
1068#ifdef HAVE_LIBKMS
1069static Bool
1070drv_destroy_front_buffer_kms(ScrnInfoPtr pScrn)
1071{
1072    modesettingPtr ms = modesettingPTR(pScrn);
1073    ScreenPtr pScreen = pScrn->pScreen;
1074    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1075
1076    /* XXX Do something with the rootPixmap.
1077     * This currently works fine but if we are getting crashes in
1078     * the fb functions after VT switches maybe look more into it.
1079     */
1080    (void)rootPixmap;
1081
1082    if (!ms->root_bo)
1083	return TRUE;
1084
1085    if (ms->fb_id != -1) {
1086	drmModeRmFB(ms->fd, ms->fb_id);
1087	ms->fb_id = -1;
1088    }
1089
1090    kms_bo_unmap(ms->root_bo);
1091    kms_bo_destroy(&ms->root_bo);
1092    return TRUE;
1093}
1094
1095static Bool
1096drv_create_front_buffer_kms(ScrnInfoPtr pScrn)
1097{
1098    modesettingPtr ms = modesettingPTR(pScrn);
1099    unsigned handle, stride;
1100    struct kms_bo *bo;
1101    unsigned attr[8];
1102    unsigned fb_id;
1103    int ret;
1104
1105    attr[0] = KMS_BO_TYPE;
1106#ifdef KMS_BO_TYPE_SCANOUT_X8R8G8B8
1107    attr[1] = KMS_BO_TYPE_SCANOUT_X8R8G8B8;
1108#else
1109    attr[1] = KMS_BO_TYPE_SCANOUT;
1110#endif
1111    attr[2] = KMS_WIDTH;
1112    attr[3] = pScrn->virtualX;
1113    attr[4] = KMS_HEIGHT;
1114    attr[5] = pScrn->virtualY;
1115    attr[6] = 0;
1116
1117    if (kms_bo_create(ms->kms, attr, &bo))
1118	return FALSE;
1119
1120    if (kms_bo_get_prop(bo, KMS_PITCH, &stride))
1121	goto err_destroy;
1122
1123    if (kms_bo_get_prop(bo, KMS_HANDLE, &handle))
1124	goto err_destroy;
1125
1126    ret = drmModeAddFB(ms->fd,
1127		       pScrn->virtualX,
1128		       pScrn->virtualY,
1129		       pScrn->depth,
1130		       pScrn->bitsPerPixel,
1131		       stride,
1132		       handle,
1133		       &fb_id);
1134    if (ret) {
1135	debug_printf("%s: failed to create framebuffer (%i, %s)",
1136		     __func__, ret, strerror(-ret));
1137	goto err_destroy;
1138    }
1139
1140    if (!drv_destroy_front_buffer_kms(pScrn))
1141	FatalError("%s: could not takedown old bo", __func__);
1142
1143    pScrn->frameX0 = 0;
1144    pScrn->frameY0 = 0;
1145    drv_adjust_frame(pScrn->scrnIndex, pScrn->frameX0, pScrn->frameY0, 0);
1146    ms->root_bo = bo;
1147    ms->fb_id = fb_id;
1148
1149    return TRUE;
1150
1151err_destroy:
1152    kms_bo_destroy(&bo);
1153    return FALSE;
1154}
1155
1156static Bool
1157drv_bind_front_buffer_kms(ScrnInfoPtr pScrn)
1158{
1159    modesettingPtr ms = modesettingPTR(pScrn);
1160    ScreenPtr pScreen = pScrn->pScreen;
1161    PixmapPtr rootPixmap = pScreen->GetScreenPixmap(pScreen);
1162    unsigned stride;
1163    void *ptr;
1164
1165    if (kms_bo_get_prop(ms->root_bo, KMS_PITCH, &stride))
1166	return FALSE;
1167
1168    if (kms_bo_map(ms->root_bo, &ptr))
1169	goto err_destroy;
1170
1171    pScreen->ModifyPixmapHeader(rootPixmap,
1172				pScrn->virtualX,
1173				pScrn->virtualY,
1174				pScreen->rootDepth,
1175				pScrn->bitsPerPixel,
1176				stride,
1177				ptr);
1178
1179    /* This a hack to work around EnableDisableFBAccess setting the pointer
1180     * the real fix would be to replace pScrn->EnableDisableFBAccess hook
1181     * and set the rootPixmap->devPrivate.ptr to something valid before that.
1182     *
1183     * But in its infinit visdome something uses either this some times before
1184     * that, so our hook doesn't get called before the crash happens.
1185     */
1186    pScrn->pixmapPrivate.ptr = ptr;
1187
1188    return TRUE;
1189
1190err_destroy:
1191    kms_bo_destroy(&ms->root_bo);
1192    return FALSE;
1193}
1194#endif /* HAVE_LIBKMS */
1195
1196static Bool drv_init_front_buffer_functions(ScrnInfoPtr pScrn)
1197{
1198    modesettingPtr ms = modesettingPTR(pScrn);
1199    if (ms->screen) {
1200	ms->destroy_front_buffer = drv_destroy_front_buffer_ga3d;
1201	ms->create_front_buffer = drv_create_front_buffer_ga3d;
1202	ms->bind_front_buffer = drv_bind_front_buffer_ga3d;
1203#ifdef HAVE_LIBKMS
1204    } else if (ms->kms) {
1205	ms->destroy_front_buffer = drv_destroy_front_buffer_kms;
1206	ms->create_front_buffer = drv_create_front_buffer_kms;
1207	ms->bind_front_buffer = drv_bind_front_buffer_kms;
1208#endif
1209    } else
1210	return FALSE;
1211
1212    return TRUE;
1213}
1214
1215CustomizerPtr xorg_customizer(ScrnInfoPtr pScrn)
1216{
1217    return modesettingPTR(pScrn)->cust;
1218}
1219
1220Bool xorg_has_gallium(ScrnInfoPtr pScrn)
1221{
1222    return modesettingPTR(pScrn)->screen != NULL;
1223}
1224
1225/* vim: set sw=4 ts=8 sts=4: */
1226