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