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