1 /*
2 * Copyright 2008 Tungsten Graphics, Inc., Cedar Park, Texas.
3 * Copyright 2011 Dave Airlie
4 * All Rights Reserved.
5 *
6 * Permission is hereby granted, free of charge, to any person obtaining a
7 * copy of this software and associated documentation files (the
8 * "Software"), to deal in the Software without restriction, including
9 * without limitation the rights to use, copy, modify, merge, publish,
10 * distribute, sub license, and/or sell copies of the Software, and to
11 * permit persons to whom the Software is furnished to do so, subject to
12 * the following conditions:
13 *
14 * The above copyright notice and this permission notice (including the
15 * next paragraph) shall be included in all copies or substantial portions
16 * of the Software.
17 *
18 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21 * IN NO EVENT SHALL TUNGSTEN GRAPHICS AND/OR ITS SUPPLIERS BE LIABLE FOR
22 * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25 *
26 *
27 * Original Author: Alan Hourihane <alanh@tungstengraphics.com>
28 * Rewrite: Dave Airlie <airlied@redhat.com>
29 *
30 */
31
32 #ifdef HAVE_DIX_CONFIG_H
33 #include "dix-config.h"
34 #endif
35
36 #include <unistd.h>
37 #include <fcntl.h>
38 #include "xf86.h"
39 #include "xf86Priv.h"
40 #include "xf86_OSproc.h"
41 #include "compiler.h"
42 #include "xf86Pci.h"
43 #include "mipointer.h"
44 #include "mipointrst.h"
45 #include "micmap.h"
46 #include "misyncshm.h"
47 #include "misyncstr.h"
48 #include <X11/extensions/randr.h>
49 #include "fb.h"
50 #include "edid.h"
51 #include "xf86i2c.h"
52 #include "xf86Crtc.h"
53 #include "miscstruct.h"
54 #include "dixstruct.h"
55 #include "shadow.h"
56 #include <X11/extensions/Xv.h>
57 #include <xorg-config.h>
58 #ifdef XSERVER_PLATFORM_BUS
59 #include "xf86platformBus.h"
60 #endif
61 #ifdef XSERVER_LIBPCIACCESS
62 #include <pciaccess.h>
63 #endif
64
65 #include "driver.h"
66
67 static void AdjustFrame(ScrnInfoPtr pScrn, int x, int y);
68 static Bool CloseScreen(ScreenPtr pScreen);
69 static Bool EnterVT(ScrnInfoPtr pScrn);
70 static void Identify(int flags);
71 static const OptionInfoRec *AvailableOptions(int chipid, int busid);
72 static ModeStatus ValidMode(ScrnInfoPtr pScrn, DisplayModePtr mode,
73 Bool verbose, int flags);
74 static void FreeScreen(ScrnInfoPtr pScrn);
75 static void LeaveVT(ScrnInfoPtr pScrn);
76 static Bool SwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode);
77 static Bool ScreenInit(ScreenPtr pScreen, int argc, char **argv);
78 static Bool PreInit(ScrnInfoPtr pScrn, int flags);
79
80 static Bool Probe(DriverPtr drv, int flags);
81 static Bool ms_pci_probe(DriverPtr driver,
82 int entity_num, struct pci_device *device,
83 intptr_t match_data);
84 static Bool ms_driver_func(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data);
85
86 static int
87 ms_shareable_fd_from_pixmap(ScreenPtr screen,
88 PixmapPtr pixmap,
89 CARD16 *stride,
90 CARD32 *size);
91 static Bool
92 ms_back_pixmap_from_fd(PixmapPtr pixmap,
93 int fd,
94 CARD16 width,
95 CARD16 height,
96 CARD16 stride, CARD8 depth, CARD8 bpp);
97
98 #ifdef XSERVER_LIBPCIACCESS
99 static const struct pci_id_match ms_device_match[] = {
100 {
101 PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY, PCI_MATCH_ANY,
102 0x00030000, 0x00ff0000, 0},
103
104 {0, 0, 0},
105 };
106 #endif
107
108 #ifndef XSERVER_PLATFORM_BUS
109 struct xf86_platform_device;
110 #endif
111
112 #ifdef XSERVER_PLATFORM_BUS
113 static Bool ms_platform_probe(DriverPtr driver,
114 int entity_num, int flags,
115 struct xf86_platform_device *device,
116 intptr_t match_data);
117 #endif
118
119 _X_EXPORT DriverRec modesetting = {
120 1,
121 "modesetting",
122 Identify,
123 Probe,
124 AvailableOptions,
125 NULL,
126 0,
127 ms_driver_func,
128 ms_device_match,
129 ms_pci_probe,
130 #ifdef XSERVER_PLATFORM_BUS
131 ms_platform_probe,
132 #endif
133 };
134
135 static SymTabRec Chipsets[] = {
136 {0, "kms"},
137 {-1, NULL}
138 };
139
140 static const OptionInfoRec Options[] = {
141 {OPTION_SW_CURSOR, "SWcursor", OPTV_BOOLEAN, {0}, FALSE},
142 {OPTION_DEVICE_PATH, "kmsdev", OPTV_STRING, {0}, FALSE},
143 {OPTION_SHADOW_FB, "ShadowFB", OPTV_BOOLEAN, {0}, FALSE},
144 {OPTION_ACCEL_METHOD, "AccelMethod", OPTV_STRING, {0}, FALSE},
145 {OPTION_PAGEFLIP, "PageFlip", OPTV_BOOLEAN, {0}, FALSE},
146 {OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE},
147 {OPTION_DOUBLE_SHADOW, "DoubleShadow", OPTV_BOOLEAN, {0}, FALSE},
148 {OPTION_ATOMIC, "Atomic", OPTV_BOOLEAN, {0}, FALSE},
149 {OPTION_USE_GAMMA_LUT, "UseGammaLUT", OPTV_BOOLEAN, {0}, FALSE},
150 {OPTION_FLIP_FB, "FlipFB", OPTV_STRING, {0}, FALSE},
151 {OPTION_FLIP_FB_RATE, "MaxFlipRate", OPTV_INTEGER, {0}, 0},
152 {OPTION_BIND_CURRENT, "BindCurrent", OPTV_BOOLEAN, {0}, FALSE},
153 {OPTION_NO_EDID, "NoEDID", OPTV_BOOLEAN, {0}, FALSE},
154 {OPTION_HOTPLUG_RESET, "HotplugReset", OPTV_BOOLEAN, {0}, FALSE},
155 {OPTION_WARM_UP, "WarmUp", OPTV_BOOLEAN, {0}, FALSE},
156 {OPTION_VIRTUAL_SIZE, "VirtualSize", OPTV_STRING, {0}, FALSE},
157 {OPTION_PADDING, "Padding", OPTV_STRING, {0}, FALSE},
158 {-1, NULL, OPTV_NONE, {0}, FALSE}
159 };
160
161 int ms_entity_index = -1;
162
163 static MODULESETUPPROTO(Setup);
164
165 static XF86ModuleVersionInfo VersRec = {
166 "modesetting",
167 MODULEVENDORSTRING,
168 MODINFOSTRING1,
169 MODINFOSTRING2,
170 XORG_VERSION_CURRENT,
171 XORG_VERSION_MAJOR,
172 XORG_VERSION_MINOR,
173 XORG_VERSION_PATCH,
174 ABI_CLASS_VIDEODRV,
175 ABI_VIDEODRV_VERSION,
176 MOD_CLASS_VIDEODRV,
177 {0, 0, 0, 0}
178 };
179
180 _X_EXPORT XF86ModuleData modesettingModuleData = { &VersRec, Setup, NULL };
181
182 static void *
Setup(void * module,void * opts,int * errmaj,int * errmin)183 Setup(void *module, void *opts, int *errmaj, int *errmin)
184 {
185 static Bool setupDone = 0;
186
187 /* This module should be loaded only once, but check to be sure.
188 */
189 if (!setupDone) {
190 setupDone = 1;
191 xf86AddDriver(&modesetting, module, HaveDriverFuncs);
192
193 /*
194 * The return value must be non-NULL on success even though there
195 * is no TearDownProc.
196 */
197 return (void *) 1;
198 }
199 else {
200 if (errmaj)
201 *errmaj = LDR_ONCEONLY;
202 return NULL;
203 }
204 }
205
206 static void
Identify(int flags)207 Identify(int flags)
208 {
209 xf86PrintChipsets("modesetting", "Driver for Modesetting Kernel Drivers",
210 Chipsets);
211 }
212
ms_ent_priv(ScrnInfoPtr scrn)213 modesettingEntPtr ms_ent_priv(ScrnInfoPtr scrn)
214 {
215 DevUnion *pPriv;
216 modesettingPtr ms = modesettingPTR(scrn);
217 pPriv = xf86GetEntityPrivate(ms->pEnt->index,
218 ms_entity_index);
219 return pPriv->ptr;
220 }
221
222 static int
get_passed_fd(void)223 get_passed_fd(void)
224 {
225 if (xf86DRMMasterFd >= 0) {
226 xf86DrvMsg(-1, X_INFO, "Using passed DRM master file descriptor %d\n", xf86DRMMasterFd);
227 return dup(xf86DRMMasterFd);
228 }
229 return -1;
230 }
231
232 static int
open_hw(const char * dev)233 open_hw(const char *dev)
234 {
235 int fd;
236
237 if ((fd = get_passed_fd()) != -1)
238 return fd;
239
240 if (dev)
241 fd = open(dev, O_RDWR | O_CLOEXEC, 0);
242 else {
243 dev = getenv("KMSDEVICE");
244 if ((NULL == dev) || ((fd = open(dev, O_RDWR | O_CLOEXEC, 0)) == -1)) {
245 dev = "/dev/dri/card0";
246 fd = open(dev, O_RDWR | O_CLOEXEC, 0);
247 }
248 }
249 if (fd == -1)
250 xf86DrvMsg(-1, X_ERROR, "open %s: %s\n", dev, strerror(errno));
251
252 return fd;
253 }
254
255 static int
check_outputs(int fd,int * count)256 check_outputs(int fd, int *count)
257 {
258 drmModeResPtr res = drmModeGetResources(fd);
259 int ret;
260
261 if (!res)
262 return FALSE;
263
264 if (count)
265 *count = res->count_connectors;
266
267 ret = res->count_connectors > 0;
268 #if defined(GLAMOR_HAS_GBM_LINEAR)
269 if (ret == FALSE) {
270 uint64_t value = 0;
271 if (drmGetCap(fd, DRM_CAP_PRIME, &value) == 0 &&
272 (value & DRM_PRIME_CAP_EXPORT))
273 ret = TRUE;
274 }
275 #endif
276 drmModeFreeResources(res);
277 return ret;
278 }
279
280 static Bool
probe_hw(const char * dev,struct xf86_platform_device * platform_dev)281 probe_hw(const char *dev, struct xf86_platform_device *platform_dev)
282 {
283 int fd;
284
285 #ifdef XF86_PDEV_SERVER_FD
286 if (platform_dev && (platform_dev->flags & XF86_PDEV_SERVER_FD)) {
287 fd = xf86_platform_device_odev_attributes(platform_dev)->fd;
288 if (fd == -1)
289 return FALSE;
290 return check_outputs(fd, NULL);
291 }
292 #endif
293
294 fd = open_hw(dev);
295 if (fd != -1) {
296 int ret = check_outputs(fd, NULL);
297
298 close(fd);
299 return ret;
300 }
301 return FALSE;
302 }
303
304 static char *
ms_DRICreatePCIBusID(const struct pci_device * dev)305 ms_DRICreatePCIBusID(const struct pci_device *dev)
306 {
307 char *busID;
308
309 if (asprintf(&busID, "pci:%04x:%02x:%02x.%d",
310 dev->domain, dev->bus, dev->dev, dev->func) == -1)
311 return NULL;
312
313 return busID;
314 }
315
316 static Bool
probe_hw_pci(const char * dev,struct pci_device * pdev)317 probe_hw_pci(const char *dev, struct pci_device *pdev)
318 {
319 int ret = FALSE, fd = open_hw(dev);
320 char *id, *devid;
321 drmSetVersion sv;
322
323 if (fd == -1)
324 return FALSE;
325
326 sv.drm_di_major = 1;
327 sv.drm_di_minor = 4;
328 sv.drm_dd_major = -1;
329 sv.drm_dd_minor = -1;
330 if (drmSetInterfaceVersion(fd, &sv)) {
331 close(fd);
332 return FALSE;
333 }
334
335 id = drmGetBusid(fd);
336 devid = ms_DRICreatePCIBusID(pdev);
337
338 if (id && devid && !strcmp(id, devid))
339 ret = check_outputs(fd, NULL);
340
341 close(fd);
342 free(id);
343 free(devid);
344 return ret;
345 }
346
347 static const OptionInfoRec *
AvailableOptions(int chipid,int busid)348 AvailableOptions(int chipid, int busid)
349 {
350 return Options;
351 }
352
353 static Bool
ms_driver_func(ScrnInfoPtr scrn,xorgDriverFuncOp op,void * data)354 ms_driver_func(ScrnInfoPtr scrn, xorgDriverFuncOp op, void *data)
355 {
356 xorgHWFlags *flag;
357
358 switch (op) {
359 case GET_REQUIRED_HW_INTERFACES:
360 flag = (CARD32 *) data;
361 (*flag) = 0;
362 return TRUE;
363 case SUPPORTS_SERVER_FDS:
364 return TRUE;
365 default:
366 return FALSE;
367 }
368 }
369
370 static void
ms_setup_scrn_hooks(ScrnInfoPtr scrn)371 ms_setup_scrn_hooks(ScrnInfoPtr scrn)
372 {
373 scrn->driverVersion = 1;
374 scrn->driverName = "modesetting";
375 scrn->name = "modeset";
376
377 scrn->Probe = NULL;
378 scrn->PreInit = PreInit;
379 scrn->ScreenInit = ScreenInit;
380 scrn->SwitchMode = SwitchMode;
381 scrn->AdjustFrame = AdjustFrame;
382 scrn->EnterVT = EnterVT;
383 scrn->LeaveVT = LeaveVT;
384 scrn->FreeScreen = FreeScreen;
385 scrn->ValidMode = ValidMode;
386 }
387
388 static void
ms_setup_entity(ScrnInfoPtr scrn,int entity_num)389 ms_setup_entity(ScrnInfoPtr scrn, int entity_num)
390 {
391 DevUnion *pPriv;
392
393 xf86SetEntitySharable(entity_num);
394
395 if (ms_entity_index == -1)
396 ms_entity_index = xf86AllocateEntityPrivateIndex();
397
398 pPriv = xf86GetEntityPrivate(entity_num,
399 ms_entity_index);
400
401 xf86SetEntityInstanceForScreen(scrn, entity_num, xf86GetNumEntityInstances(entity_num) - 1);
402
403 if (!pPriv->ptr)
404 pPriv->ptr = xnfcalloc(sizeof(modesettingEntRec), 1);
405 }
406
407 #ifdef XSERVER_LIBPCIACCESS
408 static Bool
ms_pci_probe(DriverPtr driver,int entity_num,struct pci_device * dev,intptr_t match_data)409 ms_pci_probe(DriverPtr driver,
410 int entity_num, struct pci_device *dev, intptr_t match_data)
411 {
412 ScrnInfoPtr scrn = NULL;
413
414 scrn = xf86ConfigPciEntity(scrn, 0, entity_num, NULL,
415 NULL, NULL, NULL, NULL, NULL);
416 if (scrn) {
417 const char *devpath;
418 GDevPtr devSection = xf86GetDevFromEntity(scrn->entityList[0],
419 scrn->entityInstanceList[0]);
420
421 devpath = xf86FindOptionValue(devSection->options, "kmsdev");
422 if (probe_hw_pci(devpath, dev)) {
423 ms_setup_scrn_hooks(scrn);
424
425 xf86DrvMsg(scrn->scrnIndex, X_CONFIG,
426 "claimed PCI slot %d@%d:%d:%d\n",
427 dev->bus, dev->domain, dev->dev, dev->func);
428 xf86DrvMsg(scrn->scrnIndex, X_INFO,
429 "using %s\n", devpath ? devpath : "default device");
430
431 ms_setup_entity(scrn, entity_num);
432 }
433 else
434 scrn = NULL;
435 }
436 return scrn != NULL;
437 }
438 #endif
439
440 #ifdef XSERVER_PLATFORM_BUS
441 static Bool
ms_platform_probe(DriverPtr driver,int entity_num,int flags,struct xf86_platform_device * dev,intptr_t match_data)442 ms_platform_probe(DriverPtr driver,
443 int entity_num, int flags, struct xf86_platform_device *dev,
444 intptr_t match_data)
445 {
446 ScrnInfoPtr scrn = NULL;
447 const char *path = xf86_platform_device_odev_attributes(dev)->path;
448 int scr_flags = 0;
449
450 if (flags & PLATFORM_PROBE_GPU_SCREEN)
451 scr_flags = XF86_ALLOCATE_GPU_SCREEN;
452
453 if (probe_hw(path, dev)) {
454 scrn = xf86AllocateScreen(driver, scr_flags);
455 if (xf86IsEntitySharable(entity_num))
456 xf86SetEntityShared(entity_num);
457 xf86AddEntityToScreen(scrn, entity_num);
458
459 ms_setup_scrn_hooks(scrn);
460
461 xf86DrvMsg(scrn->scrnIndex, X_INFO,
462 "using drv %s\n", path ? path : "default device");
463
464 ms_setup_entity(scrn, entity_num);
465 }
466
467 return scrn != NULL;
468 }
469 #endif
470
471 static Bool
Probe(DriverPtr drv,int flags)472 Probe(DriverPtr drv, int flags)
473 {
474 int i, numDevSections;
475 GDevPtr *devSections;
476 Bool foundScreen = FALSE;
477 const char *dev;
478 ScrnInfoPtr scrn = NULL;
479
480 if (XSERVER_PLATFORM_BUS || XSERVER_LIBPCIACCESS)
481 return FALSE;
482
483 /* For now, just bail out for PROBE_DETECT. */
484 if (flags & PROBE_DETECT)
485 return FALSE;
486
487 /*
488 * Find the config file Device sections that match this
489 * driver, and return if there are none.
490 */
491 if ((numDevSections = xf86MatchDevice("modesetting", &devSections)) <= 0) {
492 return FALSE;
493 }
494
495 for (i = 0; i < numDevSections; i++) {
496 int entity_num;
497 dev = xf86FindOptionValue(devSections[i]->options, "kmsdev");
498 if (probe_hw(dev, NULL)) {
499
500 entity_num = xf86ClaimFbSlot(drv, 0, devSections[i], TRUE);
501 scrn = xf86ConfigFbEntity(scrn, 0, entity_num, NULL, NULL, NULL, NULL);
502 }
503
504 if (scrn) {
505 foundScreen = TRUE;
506 ms_setup_scrn_hooks(scrn);
507 scrn->Probe = Probe;
508
509 xf86DrvMsg(scrn->scrnIndex, X_INFO,
510 "using %s\n", dev ? dev : "default device");
511 ms_setup_entity(scrn, entity_num);
512 }
513 }
514
515 free(devSections);
516
517 return foundScreen;
518 }
519
520 static Bool
GetRec(ScrnInfoPtr pScrn)521 GetRec(ScrnInfoPtr pScrn)
522 {
523 if (pScrn->driverPrivate)
524 return TRUE;
525
526 pScrn->driverPrivate = xnfcalloc(sizeof(modesettingRec), 1);
527
528 return TRUE;
529 }
530
531 static int
dispatch_dirty_region(ScrnInfoPtr scrn,PixmapPtr pixmap,DamagePtr damage,int fb_id)532 dispatch_dirty_region(ScrnInfoPtr scrn,
533 PixmapPtr pixmap, DamagePtr damage, int fb_id)
534 {
535 modesettingPtr ms = modesettingPTR(scrn);
536 RegionPtr dirty = DamageRegion(damage);
537 unsigned num_cliprects = REGION_NUM_RECTS(dirty);
538 int ret = 0;
539
540 #ifdef GLAMOR_HAS_GBM
541 /*
542 * HACK: Move glamor_block_handler's glamor_finish here to avoid
543 * blocking no-dirty path.
544 */
545 if (ms->drmmode.glamor)
546 glamor_finish(pixmap->drawable.pScreen);
547 #endif
548
549 if (num_cliprects) {
550 drmModeClip *clip = xallocarray(num_cliprects, sizeof(drmModeClip));
551 BoxPtr rect = REGION_RECTS(dirty);
552 int i;
553
554 if (!clip)
555 return -ENOMEM;
556
557 /* XXX no need for copy? */
558 for (i = 0; i < num_cliprects; i++, rect++) {
559 clip[i].x1 = rect->x1;
560 clip[i].y1 = rect->y1;
561 clip[i].x2 = rect->x2;
562 clip[i].y2 = rect->y2;
563 }
564
565 /* TODO query connector property to see if this is needed */
566 ret = drmModeDirtyFB(ms->fd, fb_id, clip, num_cliprects);
567
568 /* if we're swamping it with work, try one at a time */
569 if (ret == -EINVAL) {
570 for (i = 0; i < num_cliprects; i++) {
571 if ((ret = drmModeDirtyFB(ms->fd, fb_id, &clip[i], 1)) < 0)
572 break;
573 }
574 }
575
576 free(clip);
577 DamageEmpty(damage);
578 }
579 return ret;
580 }
581
582 static void
dispatch_dirty(ScreenPtr pScreen)583 dispatch_dirty(ScreenPtr pScreen)
584 {
585 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
586 modesettingPtr ms = modesettingPTR(scrn);
587 PixmapPtr pixmap = pScreen->GetScreenPixmap(pScreen);
588 int fb_id = ms->drmmode.fb_id;
589 int ret;
590
591 ret = dispatch_dirty_region(scrn, pixmap, ms->damage, fb_id);
592 if (ret == -EINVAL || ret == -ENOSYS) {
593 ms->dirty_enabled = FALSE;
594 DamageUnregister(ms->damage);
595 DamageDestroy(ms->damage);
596 ms->damage = NULL;
597 xf86DrvMsg(scrn->scrnIndex, X_INFO,
598 "Disabling kernel dirty updates, not required.\n");
599 return;
600 }
601 }
602
603 static void
dispatch_dirty_pixmap(ScrnInfoPtr scrn,xf86CrtcPtr crtc,PixmapPtr ppix)604 dispatch_dirty_pixmap(ScrnInfoPtr scrn, xf86CrtcPtr crtc, PixmapPtr ppix)
605 {
606 modesettingPtr ms = modesettingPTR(scrn);
607 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix);
608 DamagePtr damage = ppriv->slave_damage;
609 int fb_id = ppriv->fb_id;
610
611 dispatch_dirty_region(scrn, ppix, damage, fb_id);
612 }
613
614 static void
dispatch_slave_dirty(ScreenPtr pScreen)615 dispatch_slave_dirty(ScreenPtr pScreen)
616 {
617 ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
618 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
619 int c;
620
621 for (c = 0; c < xf86_config->num_crtc; c++) {
622 xf86CrtcPtr crtc = xf86_config->crtc[c];
623 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
624
625 if (!drmmode_crtc)
626 continue;
627
628 if (drmmode_crtc->prime_pixmap)
629 dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap);
630 if (drmmode_crtc->prime_pixmap_back)
631 dispatch_dirty_pixmap(scrn, crtc, drmmode_crtc->prime_pixmap_back);
632 }
633 }
634
635 static void
redisplay_dirty(ScreenPtr screen,PixmapDirtyUpdatePtr dirty,int * timeout)636 redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty, int *timeout)
637 {
638 RegionRec pixregion;
639
640 PixmapRegionInit(&pixregion, dirty->slave_dst);
641 DamageRegionAppend(&dirty->slave_dst->drawable, &pixregion);
642 PixmapSyncDirtyHelper(dirty);
643
644 if (!screen->isGPU) {
645 #ifdef GLAMOR_HAS_GBM
646 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen));
647 /*
648 * When copying from the master framebuffer to the shared pixmap,
649 * we must ensure the copy is complete before the slave starts a
650 * copy to its own framebuffer (some slaves scanout directly from
651 * the shared pixmap, but not all).
652 */
653 if (ms->drmmode.glamor)
654 glamor_finish(screen);
655 #endif
656 /* Ensure the slave processes the damage immediately */
657 if (timeout)
658 *timeout = 0;
659 }
660
661 DamageRegionProcessPending(&dirty->slave_dst->drawable);
662 RegionUninit(&pixregion);
663 }
664
665 static void
ms_dirty_update(ScreenPtr screen,int * timeout)666 ms_dirty_update(ScreenPtr screen, int *timeout)
667 {
668 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen));
669
670 RegionPtr region;
671 PixmapDirtyUpdatePtr ent;
672
673 if (xorg_list_is_empty(&screen->pixmap_dirty_list))
674 return;
675
676 xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
677 region = DamageRegion(ent->damage);
678 if (RegionNotEmpty(region)) {
679 if (!screen->isGPU) {
680 msPixmapPrivPtr ppriv =
681 msGetPixmapPriv(&ms->drmmode, ent->slave_dst->master_pixmap);
682
683 if (ppriv->notify_on_damage) {
684 ppriv->notify_on_damage = FALSE;
685
686 ent->slave_dst->drawable.pScreen->
687 SharedPixmapNotifyDamage(ent->slave_dst);
688 }
689
690 /* Requested manual updating */
691 if (ppriv->defer_dirty_update)
692 continue;
693 }
694
695 redisplay_dirty(screen, ent, timeout);
696 DamageEmpty(ent->damage);
697 }
698 }
699 }
700
701 static PixmapDirtyUpdatePtr
ms_dirty_get_ent(ScreenPtr screen,PixmapPtr slave_dst)702 ms_dirty_get_ent(ScreenPtr screen, PixmapPtr slave_dst)
703 {
704 PixmapDirtyUpdatePtr ent;
705
706 if (xorg_list_is_empty(&screen->pixmap_dirty_list))
707 return NULL;
708
709 xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
710 if (ent->slave_dst == slave_dst)
711 return ent;
712 }
713
714 return NULL;
715 }
716
717 static Bool
msBlockHandler(ScreenPtr pScreen,void * timeout)718 msBlockHandler(ScreenPtr pScreen, void *timeout)
719 {
720 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen));
721 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
722 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
723 int c;
724
725 /* HACK: Ignore the first request */
726 if (ms->warm_up) {
727 ms->warm_up = FALSE;
728 *((int *)timeout) = 16;
729 return FALSE;
730 }
731
732 if (!access(getenv("XSERVER_FREEZE_DISPLAY") ? : "", F_OK)) {
733 *((int *)timeout) = 16;
734 return FALSE;
735 }
736
737 pScreen->BlockHandler = ms->BlockHandler;
738 pScreen->BlockHandler(pScreen, timeout);
739 ms->BlockHandler = pScreen->BlockHandler;
740 pScreen->BlockHandler = (void *)msBlockHandler;
741 if (pScreen->isGPU && !ms->drmmode.reverse_prime_offload_mode)
742 dispatch_slave_dirty(pScreen);
743 else {
744 if (ms->dirty_enabled)
745 dispatch_dirty(pScreen);
746
747 for (c = 0; c < xf86_config->num_crtc; c++) {
748 xf86CrtcPtr crtc = xf86_config->crtc[c];
749 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
750
751 if (!drmmode_crtc || drmmode_flip_fb(crtc, timeout))
752 continue;
753
754 drmmode_crtc->can_flip_fb = FALSE;
755 drmmode_set_desired_modes(pScrn, &ms->drmmode, TRUE, FALSE);
756 break;
757 }
758 }
759
760 ms_dirty_update(pScreen, timeout);
761 return TRUE;
762 }
763
764 static void
msBlockHandler_oneshot(ScreenPtr pScreen,void * pTimeout)765 msBlockHandler_oneshot(ScreenPtr pScreen, void *pTimeout)
766 {
767 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
768 modesettingPtr ms = modesettingPTR(pScrn);
769
770 if (!msBlockHandler(pScreen, pTimeout))
771 return;
772
773 drmmode_set_desired_modes(pScrn, &ms->drmmode, TRUE, FALSE);
774 }
775
776 static void
FreeRec(ScrnInfoPtr pScrn)777 FreeRec(ScrnInfoPtr pScrn)
778 {
779 modesettingPtr ms;
780
781 if (!pScrn)
782 return;
783
784 ms = modesettingPTR(pScrn);
785 if (!ms)
786 return;
787
788 if (ms->fd > 0) {
789 modesettingEntPtr ms_ent;
790 int ret;
791
792 ms_ent = ms_ent_priv(pScrn);
793 ms_ent->fd_ref--;
794 if (!ms_ent->fd_ref) {
795 if (ms->pEnt->location.type == BUS_PCI)
796 ret = drmClose(ms->fd);
797 else
798 #ifdef XF86_PDEV_SERVER_FD
799 if (!(ms->pEnt->location.type == BUS_PLATFORM &&
800 (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD)))
801 #endif
802 ret = close(ms->fd);
803 (void) ret;
804 ms_ent->fd = 0;
805 }
806 }
807 pScrn->driverPrivate = NULL;
808 free(ms->drmmode.Options);
809 free(ms);
810
811 }
812
813 static void
try_enable_exa(ScrnInfoPtr pScrn)814 try_enable_exa(ScrnInfoPtr pScrn)
815 {
816 modesettingPtr ms = modesettingPTR(pScrn);
817
818 if (xf86LoadSubModule(pScrn, "exa"))
819 ms_init_exa(pScrn);
820
821 if (ms->drmmode.exa)
822 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "exa initialized\n");
823 else
824 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "exa initialization failed\n");
825 }
826
827 static void
try_enable_glamor(ScrnInfoPtr pScrn)828 try_enable_glamor(ScrnInfoPtr pScrn)
829 {
830 modesettingPtr ms = modesettingPTR(pScrn);
831 const char *accel_method_str = xf86GetOptValString(ms->drmmode.Options,
832 OPTION_ACCEL_METHOD);
833 Bool do_glamor = (!accel_method_str ||
834 strcmp(accel_method_str, "glamor") == 0);
835
836 ms->drmmode.glamor = FALSE;
837
838 #ifdef GLAMOR_HAS_GBM
839 if (ms->drmmode.force_24_32) {
840 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "Cannot use glamor with 24bpp packed fb\n");
841 return;
842 }
843
844 if (!do_glamor) {
845 xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "glamor disabled\n");
846 return;
847 }
848
849 if (xf86LoadSubModule(pScrn, GLAMOR_EGL_MODULE_NAME)) {
850 if (glamor_egl_init(pScrn, ms->fd)) {
851 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "glamor initialized\n");
852 ms->drmmode.glamor = TRUE;
853 } else {
854 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
855 "glamor initialization failed\n");
856 }
857 } else {
858 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
859 "Failed to load glamor module.\n");
860 }
861 #else
862 if (do_glamor) {
863 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
864 "No glamor support in the X Server\n");
865 }
866 #endif
867 }
868
869 static Bool
msShouldDoubleShadow(ScrnInfoPtr pScrn,modesettingPtr ms)870 msShouldDoubleShadow(ScrnInfoPtr pScrn, modesettingPtr ms)
871 {
872 Bool ret = FALSE, asked;
873 int from;
874 drmVersionPtr v;
875
876 if (!ms->drmmode.shadow_enable)
877 return FALSE;
878
879 v = drmGetVersion(ms->fd);
880 if (!strcmp(v->name, "mgag200") ||
881 !strcmp(v->name, "ast")) /* XXX || rn50 */
882 ret = TRUE;
883
884 drmFreeVersion(v);
885
886 asked = xf86GetOptValBool(ms->drmmode.Options, OPTION_DOUBLE_SHADOW, &ret);
887
888 if (asked)
889 from = X_CONFIG;
890 else
891 from = X_INFO;
892
893 xf86DrvMsg(pScrn->scrnIndex, from,
894 "Double-buffered shadow updates: %s\n", ret ? "on" : "off");
895
896 return ret;
897 }
898
899 static Bool
ms_get_drm_master_fd(ScrnInfoPtr pScrn)900 ms_get_drm_master_fd(ScrnInfoPtr pScrn)
901 {
902 EntityInfoPtr pEnt;
903 modesettingPtr ms;
904 modesettingEntPtr ms_ent;
905
906 ms = modesettingPTR(pScrn);
907 ms_ent = ms_ent_priv(pScrn);
908
909 pEnt = ms->pEnt;
910
911 if (ms_ent->fd) {
912 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
913 " reusing fd for second head\n");
914 ms->fd = ms_ent->fd;
915 ms_ent->fd_ref++;
916 return TRUE;
917 }
918
919 ms->fd_passed = FALSE;
920 if ((ms->fd = get_passed_fd()) >= 0) {
921 ms->fd_passed = TRUE;
922 return TRUE;
923 }
924
925 #ifdef XSERVER_PLATFORM_BUS
926 if (pEnt->location.type == BUS_PLATFORM) {
927 #ifdef XF86_PDEV_SERVER_FD
928 if (pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD)
929 ms->fd =
930 xf86_platform_device_odev_attributes(pEnt->location.id.plat)->
931 fd;
932 else
933 #endif
934 {
935 char *path =
936 xf86_platform_device_odev_attributes(pEnt->location.id.plat)->
937 path;
938 ms->fd = open_hw(path);
939 }
940 }
941 else
942 #endif
943 #ifdef XSERVER_LIBPCIACCESS
944 if (pEnt->location.type == BUS_PCI) {
945 char *BusID = NULL;
946 struct pci_device *PciInfo;
947
948 PciInfo = xf86GetPciInfoForEntity(ms->pEnt->index);
949 if (PciInfo) {
950 if ((BusID = ms_DRICreatePCIBusID(PciInfo)) != NULL) {
951 ms->fd = drmOpen(NULL, BusID);
952 free(BusID);
953 }
954 }
955 }
956 else
957 #endif
958 {
959 const char *devicename;
960 devicename = xf86FindOptionValue(ms->pEnt->device->options, "kmsdev");
961 ms->fd = open_hw(devicename);
962 }
963 if (ms->fd < 0)
964 return FALSE;
965
966 ms_ent->fd = ms->fd;
967 ms_ent->fd_ref = 1;
968 return TRUE;
969 }
970
971 static Bool
PreInit(ScrnInfoPtr pScrn,int flags)972 PreInit(ScrnInfoPtr pScrn, int flags)
973 {
974 modesettingPtr ms;
975 rgb defaultWeight = { 0, 0, 0 };
976 EntityInfoPtr pEnt;
977 const char *str_value;
978 uint64_t value = 0;
979 int ret;
980 int bppflags, connector_count;
981 int defaultdepth, defaultbpp;
982
983 if (pScrn->numEntities != 1)
984 return FALSE;
985
986 if (flags & PROBE_DETECT) {
987 return FALSE;
988 }
989
990 /* Allocate driverPrivate */
991 if (!GetRec(pScrn))
992 return FALSE;
993
994 pEnt = xf86GetEntityInfo(pScrn->entityList[0]);
995
996 ms = modesettingPTR(pScrn);
997 ms->SaveGeneration = -1;
998 ms->pEnt = pEnt;
999 ms->drmmode.is_secondary = FALSE;
1000 pScrn->displayWidth = 640; /* default it */
1001
1002 if (xf86IsEntityShared(pScrn->entityList[0])) {
1003 if (xf86IsPrimInitDone(pScrn->entityList[0]))
1004 ms->drmmode.is_secondary = TRUE;
1005 else
1006 xf86SetPrimInitDone(pScrn->entityList[0]);
1007 }
1008
1009 pScrn->monitor = pScrn->confScreen->monitor;
1010 pScrn->progClock = TRUE;
1011 pScrn->rgbBits = 8;
1012
1013 if (!ms_get_drm_master_fd(pScrn))
1014 return FALSE;
1015 ms->drmmode.fd = ms->fd;
1016
1017 if (!check_outputs(ms->fd, &connector_count))
1018 return FALSE;
1019
1020 drmmode_get_default_bpp(pScrn, &ms->drmmode, &defaultdepth, &defaultbpp);
1021 if (defaultdepth == 24 && defaultbpp == 24) {
1022 ms->drmmode.force_24_32 = TRUE;
1023 ms->drmmode.kbpp = 24;
1024 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1025 "Using 24bpp hw front buffer with 32bpp shadow\n");
1026 defaultbpp = 32;
1027 } else {
1028 ms->drmmode.kbpp = 0;
1029 }
1030 bppflags = PreferConvert24to32 | SupportConvert24to32 | Support32bppFb;
1031
1032 if (!xf86SetDepthBpp
1033 (pScrn, defaultdepth, defaultdepth, defaultbpp, bppflags))
1034 return FALSE;
1035
1036 switch (pScrn->depth) {
1037 case 15:
1038 case 16:
1039 case 24:
1040 case 30:
1041 break;
1042 default:
1043 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1044 "Given depth (%d) is not supported by the driver\n",
1045 pScrn->depth);
1046 return FALSE;
1047 }
1048 xf86PrintDepthBpp(pScrn);
1049 if (!ms->drmmode.kbpp)
1050 ms->drmmode.kbpp = pScrn->bitsPerPixel;
1051
1052 /* Process the options */
1053 xf86CollectOptions(pScrn, NULL);
1054 if (!(ms->drmmode.Options = malloc(sizeof(Options))))
1055 return FALSE;
1056 memcpy(ms->drmmode.Options, Options, sizeof(Options));
1057 xf86ProcessOptions(pScrn->scrnIndex, pScrn->options, ms->drmmode.Options);
1058
1059 if (!xf86SetWeight(pScrn, defaultWeight, defaultWeight))
1060 return FALSE;
1061 if (!xf86SetDefaultVisual(pScrn, -1))
1062 return FALSE;
1063
1064 if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_SW_CURSOR, FALSE)) {
1065 ms->drmmode.sw_cursor = TRUE;
1066 }
1067
1068 ms->cursor_width = 64;
1069 ms->cursor_height = 64;
1070 ret = drmGetCap(ms->fd, DRM_CAP_CURSOR_WIDTH, &value);
1071 if (!ret) {
1072 ms->cursor_width = value;
1073 }
1074 ret = drmGetCap(ms->fd, DRM_CAP_CURSOR_HEIGHT, &value);
1075 if (!ret) {
1076 ms->cursor_height = value;
1077 }
1078
1079 try_enable_glamor(pScrn);
1080
1081 if (!ms->drmmode.glamor) {
1082 Bool prefer_shadow = TRUE;
1083
1084 if (ms->drmmode.force_24_32) {
1085 prefer_shadow = TRUE;
1086 ms->drmmode.shadow_enable = TRUE;
1087 } else {
1088 ret = drmGetCap(ms->fd, DRM_CAP_DUMB_PREFER_SHADOW, &value);
1089 if (!ret) {
1090 prefer_shadow = !!value;
1091 }
1092
1093 ms->drmmode.shadow_enable =
1094 xf86ReturnOptValBool(ms->drmmode.Options, OPTION_SHADOW_FB,
1095 prefer_shadow);
1096 }
1097
1098 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1099 "ShadowFB: preferred %s, enabled %s\n",
1100 prefer_shadow ? "YES" : "NO",
1101 ms->drmmode.force_24_32 ? "FORCE" :
1102 ms->drmmode.shadow_enable ? "YES" : "NO");
1103
1104 ms->drmmode.shadow_enable2 = msShouldDoubleShadow(pScrn, ms);
1105 }
1106
1107 ms->drmmode.pageflip =
1108 xf86ReturnOptValBool(ms->drmmode.Options, OPTION_PAGEFLIP, TRUE);
1109
1110 ms->drmmode.hotplug_reset =
1111 xf86ReturnOptValBool(ms->drmmode.Options, OPTION_HOTPLUG_RESET, TRUE);
1112
1113 ms->warm_up =
1114 xf86ReturnOptValBool(ms->drmmode.Options, OPTION_WARM_UP, TRUE);
1115
1116 str_value = xf86GetOptValString(ms->drmmode.Options, OPTION_FLIP_FB);
1117 if (!str_value || !strcmp(str_value, "transformed"))
1118 ms->drmmode.fb_flip_mode = DRMMODE_FB_FLIP_TRANSFORMED;
1119 else if (!strcmp(str_value, "always"))
1120 ms->drmmode.fb_flip_mode = DRMMODE_FB_FLIP_ALWAYS;
1121 else
1122 ms->drmmode.fb_flip_mode = DRMMODE_FB_FLIP_NONE;
1123
1124 ret = -1;
1125 xf86GetOptValInteger(ms->drmmode.Options, OPTION_FLIP_FB_RATE, &ret);
1126 ms->drmmode.fb_flip_rate = ret > 0 ? ret : 0;
1127
1128 if (ms->drmmode.fb_flip_mode != DRMMODE_FB_FLIP_NONE)
1129 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
1130 "FlipFB: %s, limited to: %d fps\n",
1131 (ms->drmmode.fb_flip_mode == DRMMODE_FB_FLIP_ALWAYS ?
1132 "Always" : "Transformed"), ms->drmmode.fb_flip_rate ?: -1);
1133
1134 pScrn->capabilities = 0;
1135 ret = drmGetCap(ms->fd, DRM_CAP_PRIME, &value);
1136 if (ret == 0) {
1137 if (connector_count && (value & DRM_PRIME_CAP_IMPORT)) {
1138 pScrn->capabilities |= RR_Capability_SinkOutput;
1139 if (ms->drmmode.glamor)
1140 pScrn->capabilities |= RR_Capability_SinkOffload;
1141 }
1142 #ifdef GLAMOR_HAS_GBM_LINEAR
1143 if (value & DRM_PRIME_CAP_EXPORT && ms->drmmode.glamor)
1144 pScrn->capabilities |= RR_Capability_SourceOutput | RR_Capability_SourceOffload;
1145 #endif
1146 }
1147
1148 if (xf86ReturnOptValBool(ms->drmmode.Options, OPTION_ATOMIC, FALSE)) {
1149 ret = drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 1);
1150 ms->atomic_modeset = (ret == 0);
1151 } else {
1152 ms->atomic_modeset = FALSE;
1153 }
1154
1155 /* HACK: Force disabling atomic APIs */
1156 ms->atomic_modeset = 0;
1157
1158 /* Try to enable atomic cap, but not doing atomic modeset */
1159 drmSetClientCap(ms->fd, DRM_CLIENT_CAP_ATOMIC, 2);
1160
1161 drmSetClientCap(ms->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1);
1162
1163 ms->async_pageflip = FALSE;
1164 ret = drmGetCap(ms->fd, DRM_CAP_ASYNC_PAGE_FLIP, &value);
1165 if (ret == 0 && value == 1)
1166 ms->async_pageflip = TRUE;
1167
1168 /* HACK: The Rockchip BSP kernel might wrongly enable it */
1169 ms->async_pageflip = FALSE;
1170
1171 ms->kms_has_modifiers = FALSE;
1172 ret = drmGetCap(ms->fd, DRM_CAP_ADDFB2_MODIFIERS, &value);
1173 if (ret == 0 && value != 0)
1174 ms->kms_has_modifiers = TRUE;
1175
1176 if (drmmode_pre_init(pScrn, &ms->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
1177 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "KMS setup failed\n");
1178 goto fail;
1179 }
1180
1181 /*
1182 * If the driver can do gamma correction, it should call xf86SetGamma() here.
1183 */
1184 {
1185 Gamma zeros = { 0.0, 0.0, 0.0 };
1186
1187 if (!xf86SetGamma(pScrn, zeros)) {
1188 return FALSE;
1189 }
1190 }
1191
1192 if (!(pScrn->is_gpu && connector_count == 0) && pScrn->modes == NULL) {
1193 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "No modes.\n");
1194 return FALSE;
1195 }
1196
1197 pScrn->currentMode = pScrn->modes;
1198
1199 /* Set display resolution */
1200 xf86SetDpi(pScrn, 0, 0);
1201
1202 /* Load the required sub modules */
1203 if (!xf86LoadSubModule(pScrn, "fb")) {
1204 return FALSE;
1205 }
1206
1207 if (ms->drmmode.shadow_enable) {
1208 if (!xf86LoadSubModule(pScrn, "shadow")) {
1209 return FALSE;
1210 }
1211 }
1212
1213 return TRUE;
1214 fail:
1215 return FALSE;
1216 }
1217
1218 static void *
msShadowWindow(ScreenPtr screen,CARD32 row,CARD32 offset,int mode,CARD32 * size,void * closure)1219 msShadowWindow(ScreenPtr screen, CARD32 row, CARD32 offset, int mode,
1220 CARD32 *size, void *closure)
1221 {
1222 ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
1223 modesettingPtr ms = modesettingPTR(pScrn);
1224 int stride;
1225
1226 stride = (pScrn->displayWidth * ms->drmmode.kbpp) / 8;
1227 *size = stride;
1228
1229 return ((uint8_t *) ms->drmmode.front_bo.dumb->ptr + row * stride + offset);
1230 }
1231
1232 /* somewhat arbitrary tile size, in pixels */
1233 #define TILE 16
1234
1235 static int
msUpdateIntersect(modesettingPtr ms,shadowBufPtr pBuf,BoxPtr box,xRectangle * prect)1236 msUpdateIntersect(modesettingPtr ms, shadowBufPtr pBuf, BoxPtr box,
1237 xRectangle *prect)
1238 {
1239 int i, dirty = 0, stride = pBuf->pPixmap->devKind, cpp = ms->drmmode.cpp;
1240 int width = (box->x2 - box->x1) * cpp;
1241 unsigned char *old, *new;
1242
1243 old = ms->drmmode.shadow_fb2;
1244 old += (box->y1 * stride) + (box->x1 * cpp);
1245 new = ms->drmmode.shadow_fb;
1246 new += (box->y1 * stride) + (box->x1 * cpp);
1247
1248 for (i = box->y2 - box->y1 - 1; i >= 0; i--) {
1249 unsigned char *o = old + i * stride,
1250 *n = new + i * stride;
1251 if (memcmp(o, n, width) != 0) {
1252 dirty = 1;
1253 memcpy(o, n, width);
1254 }
1255 }
1256
1257 if (dirty) {
1258 prect->x = box->x1;
1259 prect->y = box->y1;
1260 prect->width = box->x2 - box->x1;
1261 prect->height = box->y2 - box->y1;
1262 }
1263
1264 return dirty;
1265 }
1266
1267 static void
msUpdatePacked(ScreenPtr pScreen,shadowBufPtr pBuf)1268 msUpdatePacked(ScreenPtr pScreen, shadowBufPtr pBuf)
1269 {
1270 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1271 modesettingPtr ms = modesettingPTR(pScrn);
1272 Bool use_3224 = ms->drmmode.force_24_32 && pScrn->bitsPerPixel == 32;
1273
1274 if (ms->drmmode.shadow_enable2 && ms->drmmode.shadow_fb2) do {
1275 RegionPtr damage = DamageRegion(pBuf->pDamage), tiles;
1276 BoxPtr extents = RegionExtents(damage);
1277 xRectangle *prect;
1278 int nrects;
1279 int i, j, tx1, tx2, ty1, ty2;
1280
1281 tx1 = extents->x1 / TILE;
1282 tx2 = (extents->x2 + TILE - 1) / TILE;
1283 ty1 = extents->y1 / TILE;
1284 ty2 = (extents->y2 + TILE - 1) / TILE;
1285
1286 nrects = (tx2 - tx1) * (ty2 - ty1);
1287 if (!(prect = calloc(nrects, sizeof(xRectangle))))
1288 break;
1289
1290 nrects = 0;
1291 for (j = ty2 - 1; j >= ty1; j--) {
1292 for (i = tx2 - 1; i >= tx1; i--) {
1293 BoxRec box;
1294
1295 box.x1 = max(i * TILE, extents->x1);
1296 box.y1 = max(j * TILE, extents->y1);
1297 box.x2 = min((i+1) * TILE, extents->x2);
1298 box.y2 = min((j+1) * TILE, extents->y2);
1299
1300 if (RegionContainsRect(damage, &box) != rgnOUT) {
1301 if (msUpdateIntersect(ms, pBuf, &box, prect + nrects)) {
1302 nrects++;
1303 }
1304 }
1305 }
1306 }
1307
1308 tiles = RegionFromRects(nrects, prect, CT_NONE);
1309 RegionIntersect(damage, damage, tiles);
1310 RegionDestroy(tiles);
1311 free(prect);
1312 } while (0);
1313
1314 if (ms->drmmode.exa)
1315 ms_exa_prepare_access(pBuf->pPixmap, 0);
1316
1317 if (use_3224)
1318 shadowUpdate32to24(pScreen, pBuf);
1319 else
1320 shadowUpdatePacked(pScreen, pBuf);
1321
1322 if (ms->drmmode.exa)
1323 ms_exa_finish_access(pBuf->pPixmap, 0);
1324 }
1325
1326 static Bool
msEnableSharedPixmapFlipping(RRCrtcPtr crtc,PixmapPtr front,PixmapPtr back)1327 msEnableSharedPixmapFlipping(RRCrtcPtr crtc, PixmapPtr front, PixmapPtr back)
1328 {
1329 ScreenPtr screen = crtc->pScreen;
1330 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1331 modesettingPtr ms = modesettingPTR(scrn);
1332 EntityInfoPtr pEnt = ms->pEnt;
1333 xf86CrtcPtr xf86Crtc = crtc->devPrivate;
1334
1335 if (!xf86Crtc)
1336 return FALSE;
1337
1338 /* Not supported if we can't flip */
1339 if (!ms->drmmode.pageflip)
1340 return FALSE;
1341
1342 /* Not currently supported with reverse PRIME */
1343 if (ms->drmmode.reverse_prime_offload_mode)
1344 return FALSE;
1345
1346 #ifdef XSERVER_PLATFORM_BUS
1347 if (pEnt->location.type == BUS_PLATFORM) {
1348 char *syspath =
1349 xf86_platform_device_odev_attributes(pEnt->location.id.plat)->
1350 syspath;
1351
1352 /* Not supported for devices using USB transport due to misbehaved
1353 * vblank events */
1354 if (syspath && strstr(syspath, "usb"))
1355 return FALSE;
1356
1357 /* EVDI uses USB transport but is platform device, not usb.
1358 * Blacklist it explicitly */
1359 if (syspath && strstr(syspath, "evdi"))
1360 return FALSE;
1361 }
1362 #endif
1363
1364 return drmmode_EnableSharedPixmapFlipping(xf86Crtc, &ms->drmmode,
1365 front, back);
1366 }
1367
1368 static void
msDisableSharedPixmapFlipping(RRCrtcPtr crtc)1369 msDisableSharedPixmapFlipping(RRCrtcPtr crtc)
1370 {
1371 ScreenPtr screen = crtc->pScreen;
1372 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1373 modesettingPtr ms = modesettingPTR(scrn);
1374 xf86CrtcPtr xf86Crtc = crtc->devPrivate;
1375
1376 if (xf86Crtc)
1377 drmmode_DisableSharedPixmapFlipping(xf86Crtc, &ms->drmmode);
1378 }
1379
1380 static Bool
msStartFlippingPixmapTracking(RRCrtcPtr crtc,DrawablePtr src,PixmapPtr slave_dst1,PixmapPtr slave_dst2,int x,int y,int dst_x,int dst_y,Rotation rotation)1381 msStartFlippingPixmapTracking(RRCrtcPtr crtc, DrawablePtr src,
1382 PixmapPtr slave_dst1, PixmapPtr slave_dst2,
1383 int x, int y, int dst_x, int dst_y,
1384 Rotation rotation)
1385 {
1386 ScreenPtr pScreen = src->pScreen;
1387 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen));
1388
1389 msPixmapPrivPtr ppriv1 = msGetPixmapPriv(&ms->drmmode, slave_dst1->master_pixmap),
1390 ppriv2 = msGetPixmapPriv(&ms->drmmode, slave_dst2->master_pixmap);
1391
1392 if (!PixmapStartDirtyTracking(src, slave_dst1, x, y,
1393 dst_x, dst_y, rotation)) {
1394 return FALSE;
1395 }
1396
1397 if (!PixmapStartDirtyTracking(src, slave_dst2, x, y,
1398 dst_x, dst_y, rotation)) {
1399 PixmapStopDirtyTracking(src, slave_dst1);
1400 return FALSE;
1401 }
1402
1403 ppriv1->slave_src = src;
1404 ppriv2->slave_src = src;
1405
1406 ppriv1->dirty = ms_dirty_get_ent(pScreen, slave_dst1);
1407 ppriv2->dirty = ms_dirty_get_ent(pScreen, slave_dst2);
1408
1409 ppriv1->defer_dirty_update = TRUE;
1410 ppriv2->defer_dirty_update = TRUE;
1411
1412 return TRUE;
1413 }
1414
1415 static Bool
msPresentSharedPixmap(PixmapPtr slave_dst)1416 msPresentSharedPixmap(PixmapPtr slave_dst)
1417 {
1418 ScreenPtr pScreen = slave_dst->master_pixmap->drawable.pScreen;
1419 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen));
1420
1421 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, slave_dst->master_pixmap);
1422
1423 RegionPtr region = DamageRegion(ppriv->dirty->damage);
1424
1425 if (RegionNotEmpty(region)) {
1426 redisplay_dirty(ppriv->slave_src->pScreen, ppriv->dirty, NULL);
1427 DamageEmpty(ppriv->dirty->damage);
1428
1429 return TRUE;
1430 }
1431
1432 return FALSE;
1433 }
1434
1435 static Bool
msStopFlippingPixmapTracking(DrawablePtr src,PixmapPtr slave_dst1,PixmapPtr slave_dst2)1436 msStopFlippingPixmapTracking(DrawablePtr src,
1437 PixmapPtr slave_dst1, PixmapPtr slave_dst2)
1438 {
1439 ScreenPtr pScreen = src->pScreen;
1440 modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(pScreen));
1441
1442 msPixmapPrivPtr ppriv1 = msGetPixmapPriv(&ms->drmmode, slave_dst1->master_pixmap),
1443 ppriv2 = msGetPixmapPriv(&ms->drmmode, slave_dst2->master_pixmap);
1444
1445 Bool ret = TRUE;
1446
1447 ret &= PixmapStopDirtyTracking(src, slave_dst1);
1448 ret &= PixmapStopDirtyTracking(src, slave_dst2);
1449
1450 if (ret) {
1451 ppriv1->slave_src = NULL;
1452 ppriv2->slave_src = NULL;
1453
1454 ppriv1->dirty = NULL;
1455 ppriv2->dirty = NULL;
1456
1457 ppriv1->defer_dirty_update = FALSE;
1458 ppriv2->defer_dirty_update = FALSE;
1459 }
1460
1461 return ret;
1462 }
1463
1464 static Bool
CreateScreenResources(ScreenPtr pScreen)1465 CreateScreenResources(ScreenPtr pScreen)
1466 {
1467 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1468 modesettingPtr ms = modesettingPTR(pScrn);
1469 PixmapPtr rootPixmap;
1470 Bool ret;
1471 void *pixels = NULL;
1472 int err;
1473
1474 pScreen->CreateScreenResources = ms->createScreenResources;
1475 ret = pScreen->CreateScreenResources(pScreen);
1476 pScreen->CreateScreenResources = CreateScreenResources;
1477
1478 if (!drmmode_set_desired_modes(pScrn, &ms->drmmode, pScrn->is_gpu, FALSE))
1479 return FALSE;
1480
1481 if (!drmmode_handle_new_screen_pixmap(&ms->drmmode))
1482 return FALSE;
1483
1484 drmmode_uevent_init(pScrn, &ms->drmmode);
1485
1486 if (!ms->drmmode.sw_cursor)
1487 drmmode_map_cursor_bos(pScrn, &ms->drmmode);
1488
1489 if (!ms->drmmode.gbm && !ms->drmmode.exa) {
1490 pixels = drmmode_map_front_bo(&ms->drmmode);
1491 if (!pixels)
1492 return FALSE;
1493
1494 drmmode_handle_new_screen_pixmap(&ms->drmmode);
1495 }
1496
1497 rootPixmap = pScreen->GetScreenPixmap(pScreen);
1498
1499 if (ms->drmmode.shadow_enable)
1500 pixels = ms->drmmode.shadow_fb;
1501
1502 if (ms->drmmode.shadow_enable2) {
1503 ms->drmmode.shadow_fb2 = calloc(1, pScrn->displayWidth * pScrn->virtualY * ((pScrn->bitsPerPixel + 7) >> 3));
1504 if (!ms->drmmode.shadow_fb2)
1505 ms->drmmode.shadow_enable2 = FALSE;
1506 }
1507
1508 if (!pScreen->ModifyPixmapHeader(rootPixmap, -1, -1, -1, -1, -1, pixels))
1509 FatalError("Couldn't adjust screen pixmap\n");
1510
1511 if (ms->drmmode.shadow_enable) {
1512 if (!shadowAdd(pScreen, rootPixmap, msUpdatePacked, msShadowWindow,
1513 0, 0))
1514 return FALSE;
1515 }
1516
1517 err = drmModeDirtyFB(ms->fd, ms->drmmode.fb_id, NULL, 0);
1518
1519 if (err != -EINVAL && err != -ENOSYS) {
1520 ms->damage = DamageCreate(NULL, NULL, DamageReportNone, TRUE,
1521 pScreen, rootPixmap);
1522
1523 if (ms->damage) {
1524 DamageRegister(&rootPixmap->drawable, ms->damage);
1525 ms->dirty_enabled = TRUE;
1526 xf86DrvMsg(pScrn->scrnIndex, X_INFO, "Damage tracking initialized\n");
1527 }
1528 else {
1529 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1530 "Failed to create screen damage record\n");
1531 return FALSE;
1532 }
1533 }
1534
1535 if (dixPrivateKeyRegistered(rrPrivKey)) {
1536 rrScrPrivPtr pScrPriv = rrGetScrPriv(pScreen);
1537
1538 pScrPriv->rrEnableSharedPixmapFlipping = msEnableSharedPixmapFlipping;
1539 pScrPriv->rrDisableSharedPixmapFlipping = msDisableSharedPixmapFlipping;
1540
1541 pScrPriv->rrStartFlippingPixmapTracking = msStartFlippingPixmapTracking;
1542 }
1543
1544 return ret;
1545 }
1546
1547 static Bool
msShadowInit(ScreenPtr pScreen)1548 msShadowInit(ScreenPtr pScreen)
1549 {
1550 if (!shadowSetup(pScreen)) {
1551 return FALSE;
1552 }
1553 return TRUE;
1554 }
1555
1556 static Bool
msSharePixmapBacking(PixmapPtr ppix,ScreenPtr screen,void ** handle)1557 msSharePixmapBacking(PixmapPtr ppix, ScreenPtr screen, void **handle)
1558 {
1559 int ret = -1;
1560 CARD16 stride;
1561 CARD32 size;
1562 ret = ms_shareable_fd_from_pixmap(ppix->drawable.pScreen, ppix,
1563 &stride, &size);
1564 if (ret == -1)
1565 return FALSE;
1566
1567 *handle = (void *)(long)(ret);
1568 return TRUE;
1569 }
1570
1571 static Bool
msSetSharedPixmapBacking(PixmapPtr ppix,void * fd_handle)1572 msSetSharedPixmapBacking(PixmapPtr ppix, void *fd_handle)
1573 {
1574 ScreenPtr screen = ppix->drawable.pScreen;
1575 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1576 modesettingPtr ms = modesettingPTR(scrn);
1577 Bool ret;
1578 int ihandle = (int) (long) fd_handle;
1579
1580 if (ihandle == -1)
1581 if (!ms->drmmode.reverse_prime_offload_mode)
1582 return drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, 0, 0);
1583
1584 if (ms->drmmode.reverse_prime_offload_mode) {
1585 ret = ms_back_pixmap_from_fd(ppix, ihandle,
1586 ppix->drawable.width,
1587 ppix->drawable.height,
1588 ppix->devKind, ppix->drawable.depth,
1589 ppix->drawable.bitsPerPixel);
1590 } else {
1591 int size = ppix->devKind * ppix->drawable.height;
1592 ret = drmmode_SetSlaveBO(ppix, &ms->drmmode, ihandle, ppix->devKind, size);
1593 }
1594 if (ret == FALSE)
1595 return ret;
1596
1597 return TRUE;
1598 }
1599
1600 static Bool
msRequestSharedPixmapNotifyDamage(PixmapPtr ppix)1601 msRequestSharedPixmapNotifyDamage(PixmapPtr ppix)
1602 {
1603 ScreenPtr screen = ppix->drawable.pScreen;
1604 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1605 modesettingPtr ms = modesettingPTR(scrn);
1606
1607 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix->master_pixmap);
1608
1609 ppriv->notify_on_damage = TRUE;
1610
1611 return TRUE;
1612 }
1613
1614 static Bool
msSharedPixmapNotifyDamage(PixmapPtr ppix)1615 msSharedPixmapNotifyDamage(PixmapPtr ppix)
1616 {
1617 Bool ret = FALSE;
1618 int c;
1619
1620 ScreenPtr screen = ppix->drawable.pScreen;
1621 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
1622 modesettingPtr ms = modesettingPTR(scrn);
1623 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1624
1625 msPixmapPrivPtr ppriv = msGetPixmapPriv(&ms->drmmode, ppix);
1626
1627 if (!ppriv->wait_for_damage)
1628 return ret;
1629 ppriv->wait_for_damage = FALSE;
1630
1631 for (c = 0; c < xf86_config->num_crtc; c++) {
1632 xf86CrtcPtr crtc = xf86_config->crtc[c];
1633 drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1634
1635 if (!drmmode_crtc)
1636 continue;
1637 if (!(drmmode_crtc->prime_pixmap && drmmode_crtc->prime_pixmap_back))
1638 continue;
1639
1640 // Received damage on master screen pixmap, schedule present on vblank
1641 ret |= drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, &ms->drmmode);
1642 }
1643
1644 return ret;
1645 }
1646
1647 static Bool
SetMaster(ScrnInfoPtr pScrn)1648 SetMaster(ScrnInfoPtr pScrn)
1649 {
1650 modesettingPtr ms = modesettingPTR(pScrn);
1651 int ret;
1652
1653 #ifdef XF86_PDEV_SERVER_FD
1654 if (ms->pEnt->location.type == BUS_PLATFORM &&
1655 (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD))
1656 return TRUE;
1657 #endif
1658
1659 if (ms->fd_passed)
1660 return TRUE;
1661
1662 ret = drmSetMaster(ms->fd);
1663 if (ret)
1664 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "drmSetMaster failed: %s\n",
1665 strerror(errno));
1666
1667 return ret == 0;
1668 }
1669
1670 /* When the root window is created, initialize the screen contents from
1671 * console if -background none was specified on the command line
1672 */
1673 static Bool
CreateWindow_oneshot(WindowPtr pWin)1674 CreateWindow_oneshot(WindowPtr pWin)
1675 {
1676 ScreenPtr pScreen = pWin->drawable.pScreen;
1677 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1678 modesettingPtr ms = modesettingPTR(pScrn);
1679 Bool ret;
1680
1681 pScreen->CreateWindow = ms->CreateWindow;
1682 ret = pScreen->CreateWindow(pWin);
1683
1684 if (ret)
1685 drmmode_copy_fb(pScrn, &ms->drmmode);
1686 return ret;
1687 }
1688
1689 static Bool
ScreenInit(ScreenPtr pScreen,int argc,char ** argv)1690 ScreenInit(ScreenPtr pScreen, int argc, char **argv)
1691 {
1692 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
1693 modesettingPtr ms = modesettingPTR(pScrn);
1694 VisualPtr visual;
1695 const char *str_value;
1696
1697 pScrn->pScreen = pScreen;
1698
1699 #if 0 // The Rockchip BSP kernels doesn't have DRM permit checking.
1700 if (!SetMaster(pScrn))
1701 return FALSE;
1702 #endif
1703
1704 #ifdef GLAMOR_HAS_GBM
1705 if (ms->drmmode.glamor)
1706 ms->drmmode.gbm = glamor_egl_get_gbm_device(pScreen);
1707 #endif
1708
1709 /* HW dependent - FIXME */
1710 pScrn->displayWidth = pScrn->virtualX;
1711 if (!drmmode_create_initial_bos(pScrn, &ms->drmmode))
1712 return FALSE;
1713
1714 if (ms->drmmode.shadow_enable) {
1715 ms->drmmode.shadow_fb =
1716 calloc(1,
1717 pScrn->displayWidth * pScrn->virtualY *
1718 ((pScrn->bitsPerPixel + 7) >> 3));
1719 if (!ms->drmmode.shadow_fb)
1720 ms->drmmode.shadow_enable = FALSE;
1721 }
1722
1723 miClearVisualTypes();
1724
1725 if (!miSetVisualTypes(pScrn->depth,
1726 miGetDefaultVisualMask(pScrn->depth),
1727 pScrn->rgbBits, pScrn->defaultVisual))
1728 return FALSE;
1729
1730 if (!miSetPixmapDepths())
1731 return FALSE;
1732
1733 if (!dixRegisterScreenSpecificPrivateKey
1734 (pScreen, &ms->drmmode.pixmapPrivateKeyRec, PRIVATE_PIXMAP,
1735 sizeof(msPixmapPrivRec))) {
1736 return FALSE;
1737 }
1738
1739 pScrn->memPhysBase = 0;
1740 pScrn->fbOffset = 0;
1741
1742 if (!fbScreenInit(pScreen, NULL,
1743 pScrn->virtualX, pScrn->virtualY,
1744 pScrn->xDpi, pScrn->yDpi,
1745 pScrn->displayWidth, pScrn->bitsPerPixel))
1746 return FALSE;
1747
1748 if (pScrn->bitsPerPixel > 8) {
1749 /* Fixup RGB ordering */
1750 visual = pScreen->visuals + pScreen->numVisuals;
1751 while (--visual >= pScreen->visuals) {
1752 if ((visual->class | DynamicClass) == DirectColor) {
1753 visual->offsetRed = pScrn->offset.red;
1754 visual->offsetGreen = pScrn->offset.green;
1755 visual->offsetBlue = pScrn->offset.blue;
1756 visual->redMask = pScrn->mask.red;
1757 visual->greenMask = pScrn->mask.green;
1758 visual->blueMask = pScrn->mask.blue;
1759 }
1760 }
1761 }
1762
1763 fbPictureInit(pScreen, NULL, 0);
1764
1765 if (drmmode_init(pScrn, &ms->drmmode) == FALSE) {
1766 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1767 "Failed to initialize glamor at ScreenInit() time.\n");
1768 return FALSE;
1769 }
1770
1771 if (ms->drmmode.shadow_enable && !msShadowInit(pScreen)) {
1772 xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "shadow fb init failed\n");
1773 return FALSE;
1774 }
1775
1776 ms->createScreenResources = pScreen->CreateScreenResources;
1777 pScreen->CreateScreenResources = CreateScreenResources;
1778
1779 xf86SetBlackWhitePixels(pScreen);
1780
1781 str_value = xf86GetOptValString(ms->drmmode.Options,
1782 OPTION_ACCEL_METHOD);
1783 if (str_value && !strcmp(str_value, "exa"))
1784 try_enable_exa(pScrn);
1785
1786 xf86SetBackingStore(pScreen);
1787 xf86SetSilkenMouse(pScreen);
1788 miDCInitialize(pScreen, xf86GetPointerScreenFuncs());
1789
1790 /* If pageflip is enabled hook the screen's cursor-sprite (swcursor) funcs.
1791 * So that we can disabe page-flipping on fallback to a swcursor. */
1792 if (ms->drmmode.pageflip) {
1793 miPointerScreenPtr PointPriv =
1794 dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
1795
1796 if (!dixRegisterScreenPrivateKey(&ms->drmmode.spritePrivateKeyRec,
1797 pScreen, PRIVATE_DEVICE,
1798 sizeof(msSpritePrivRec)))
1799 return FALSE;
1800
1801 ms->SpriteFuncs = PointPriv->spriteFuncs;
1802 PointPriv->spriteFuncs = &drmmode_sprite_funcs;
1803 }
1804
1805 /* Need to extend HWcursor support to handle mask interleave */
1806 if (!ms->drmmode.sw_cursor)
1807 xf86_cursors_init(pScreen, ms->cursor_width, ms->cursor_height,
1808 HARDWARE_CURSOR_SOURCE_MASK_INTERLEAVE_64 |
1809 HARDWARE_CURSOR_UPDATE_UNHIDDEN |
1810 HARDWARE_CURSOR_ARGB);
1811
1812 /* Must force it before EnterVT, so we are in control of VT and
1813 * later memory should be bound when allocating, e.g rotate_mem */
1814 pScrn->vtSema = TRUE;
1815
1816 if (serverGeneration == 1 && bgNoneRoot) {
1817 ms->CreateWindow = pScreen->CreateWindow;
1818 pScreen->CreateWindow = CreateWindow_oneshot;
1819 }
1820
1821 pScreen->SaveScreen = xf86SaveScreen;
1822 ms->CloseScreen = pScreen->CloseScreen;
1823 pScreen->CloseScreen = CloseScreen;
1824
1825 ms->BlockHandler = pScreen->BlockHandler;
1826 pScreen->BlockHandler = msBlockHandler_oneshot;
1827
1828 pScreen->SharePixmapBacking = msSharePixmapBacking;
1829 pScreen->SetSharedPixmapBacking = msSetSharedPixmapBacking;
1830 pScreen->StartPixmapTracking = PixmapStartDirtyTracking;
1831 pScreen->StopPixmapTracking = PixmapStopDirtyTracking;
1832
1833 pScreen->SharedPixmapNotifyDamage = msSharedPixmapNotifyDamage;
1834 pScreen->RequestSharedPixmapNotifyDamage =
1835 msRequestSharedPixmapNotifyDamage;
1836
1837 pScreen->PresentSharedPixmap = msPresentSharedPixmap;
1838 pScreen->StopFlippingPixmapTracking = msStopFlippingPixmapTracking;
1839
1840 if (!xf86CrtcScreenInit(pScreen))
1841 return FALSE;
1842
1843 if (!drmmode_setup_colormap(pScreen, pScrn))
1844 return FALSE;
1845
1846 if (ms->atomic_modeset)
1847 xf86DPMSInit(pScreen, drmmode_set_dpms, 0);
1848 else
1849 xf86DPMSInit(pScreen, xf86DPMSSet, 0);
1850
1851 #ifdef GLAMOR_HAS_GBM
1852 if (ms->drmmode.glamor) {
1853 ms->adaptor = glamor_xv_init(pScreen, 16);
1854 if (ms->adaptor != NULL) {
1855 xf86XVScreenInit(pScreen, &ms->adaptor, 1);
1856 } else {
1857 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1858 "Failed to initialize XV support.\n");
1859 }
1860 }
1861 #endif
1862
1863 if (ms->drmmode.exa) {
1864 ms->adaptor = ms_exa_xv_init(pScreen, 16);
1865 if (ms->adaptor != NULL) {
1866 xf86XVScreenInit(pScreen, &ms->adaptor, 1);
1867 } else {
1868 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1869 "Failed to initialize XV support.\n");
1870 }
1871 }
1872
1873 if (serverGeneration == 1)
1874 xf86ShowUnusedOptions(pScrn->scrnIndex, pScrn->options);
1875
1876 if (!ms_vblank_screen_init(pScreen)) {
1877 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1878 "Failed to initialize vblank support.\n");
1879 return FALSE;
1880 }
1881
1882 if (ms->drmmode.glamor || ms->drmmode.exa) {
1883 if (!(ms->drmmode.dri2_enable = ms_dri2_screen_init(pScreen))) {
1884 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1885 "Failed to initialize the DRI2 extension.\n");
1886 }
1887
1888 if (!(ms->drmmode.present_enable = ms_present_screen_init(pScreen))) {
1889 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1890 "Failed to initialize the Present extension.\n");
1891 }
1892 /* enable reverse prime if we are a GPU screen, and accelerated, and not
1893 * i915. i915 is happy scanning out from sysmem. */
1894 if (pScreen->isGPU) {
1895 drmVersionPtr version;
1896
1897 /* enable if we are an accelerated GPU screen */
1898 ms->drmmode.reverse_prime_offload_mode = TRUE;
1899
1900 /* disable if we detect i915 */
1901 if ((version = drmGetVersion(ms->drmmode.fd))) {
1902 if (!strncmp("i915", version->name, version->name_len)) {
1903 ms->drmmode.reverse_prime_offload_mode = FALSE;
1904 }
1905 drmFreeVersion(version);
1906 }
1907 }
1908 }
1909
1910 #ifdef DRI3
1911 if (ms->drmmode.exa) {
1912 if (!ms_exa_dri3_init(pScreen)) {
1913 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1914 "Failed to initialize the DRI3 extension.\n");
1915 }
1916 }
1917 #endif
1918
1919 #if XSYNC
1920 if (ms->drmmode.exa) {
1921 #ifdef HAVE_XSHMFENCE
1922 if (!miSyncShmScreenInit(pScreen)) {
1923 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1924 "Failed to initialize sync support.\n");
1925 }
1926 #else
1927 if (!miSyncSetup(pScreen)) {
1928 xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
1929 "Failed to initialize sync support.\n");
1930 }
1931 #endif
1932 }
1933 #endif
1934
1935 pScrn->vtSema = TRUE;
1936
1937 return TRUE;
1938 }
1939
1940 static void
AdjustFrame(ScrnInfoPtr pScrn,int x,int y)1941 AdjustFrame(ScrnInfoPtr pScrn, int x, int y)
1942 {
1943 modesettingPtr ms = modesettingPTR(pScrn);
1944
1945 drmmode_adjust_frame(pScrn, &ms->drmmode, x, y);
1946 }
1947
1948 static void
FreeScreen(ScrnInfoPtr pScrn)1949 FreeScreen(ScrnInfoPtr pScrn)
1950 {
1951 FreeRec(pScrn);
1952 }
1953
1954 static void
LeaveVT(ScrnInfoPtr pScrn)1955 LeaveVT(ScrnInfoPtr pScrn)
1956 {
1957 modesettingPtr ms = modesettingPTR(pScrn);
1958
1959 xf86_hide_cursors(pScrn);
1960
1961 pScrn->vtSema = FALSE;
1962
1963 #ifdef XF86_PDEV_SERVER_FD
1964 if (ms->pEnt->location.type == BUS_PLATFORM &&
1965 (ms->pEnt->location.id.plat->flags & XF86_PDEV_SERVER_FD))
1966 return;
1967 #endif
1968
1969 if (!ms->fd_passed)
1970 drmDropMaster(ms->fd);
1971 }
1972
1973 /*
1974 * This gets called when gaining control of the VT, and from ScreenInit().
1975 */
1976 static Bool
EnterVT(ScrnInfoPtr pScrn)1977 EnterVT(ScrnInfoPtr pScrn)
1978 {
1979 modesettingPtr ms = modesettingPTR(pScrn);
1980
1981 pScrn->vtSema = TRUE;
1982
1983 SetMaster(pScrn);
1984
1985 drmmode_update_kms_state(&ms->drmmode);
1986
1987 /* allow not all modes to be set successfully since some events might have
1988 * happened while not being master that could prevent the previous
1989 * configuration from being re-applied.
1990 */
1991 if (!drmmode_set_desired_modes(pScrn, &ms->drmmode, TRUE, TRUE)) {
1992 xf86DisableUnusedFunctions(pScrn);
1993
1994 /* TODO: check that at least one screen is on, to allow the user to fix
1995 * their setup if all modeset failed...
1996 */
1997
1998 /* Tell the desktop environment that something changed, so that they
1999 * can hopefully correct the situation
2000 */
2001 RRSetChanged(xf86ScrnToScreen(pScrn));
2002 RRTellChanged(xf86ScrnToScreen(pScrn));
2003 }
2004
2005 return TRUE;
2006 }
2007
2008 static Bool
SwitchMode(ScrnInfoPtr pScrn,DisplayModePtr mode)2009 SwitchMode(ScrnInfoPtr pScrn, DisplayModePtr mode)
2010 {
2011 return xf86SetSingleMode(pScrn, mode, RR_Rotate_0);
2012 }
2013
2014 static Bool
CloseScreen(ScreenPtr pScreen)2015 CloseScreen(ScreenPtr pScreen)
2016 {
2017 ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
2018 modesettingPtr ms = modesettingPTR(pScrn);
2019 modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
2020
2021 xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2022 int c;
2023
2024 /* HACK: All filters would be reset after screen closed */
2025 for (c = 0; c < xf86_config->num_crtc; c++) {
2026 xf86CrtcPtr crtc = xf86_config->crtc[c];
2027 crtc->transform.filter = NULL;
2028 }
2029
2030 /* Clear mask of assigned crtc's in this generation */
2031 ms_ent->assigned_crtcs = 0;
2032
2033 #ifdef DRI3
2034 if (ms->drmmode.dri3_device_name) {
2035 free(ms->drmmode.dri3_device_name);
2036 ms->drmmode.dri3_device_name = NULL;
2037 }
2038 #endif
2039
2040 if (ms->drmmode.dri2_enable) {
2041 ms_dri2_close_screen(pScreen);
2042 }
2043
2044 ms_vblank_close_screen(pScreen);
2045
2046 if (ms->damage) {
2047 DamageUnregister(ms->damage);
2048 DamageDestroy(ms->damage);
2049 ms->damage = NULL;
2050 }
2051
2052 if (ms->drmmode.shadow_enable) {
2053 shadowRemove(pScreen, pScreen->GetScreenPixmap(pScreen));
2054 free(ms->drmmode.shadow_fb);
2055 ms->drmmode.shadow_fb = NULL;
2056 free(ms->drmmode.shadow_fb2);
2057 ms->drmmode.shadow_fb2 = NULL;
2058 }
2059
2060 drmmode_uevent_fini(pScrn, &ms->drmmode);
2061
2062 drmmode_free_bos(pScrn, &ms->drmmode);
2063
2064 if (ms->drmmode.pageflip) {
2065 miPointerScreenPtr PointPriv =
2066 dixLookupPrivate(&pScreen->devPrivates, miPointerScreenKey);
2067
2068 if (PointPriv->spriteFuncs == &drmmode_sprite_funcs)
2069 PointPriv->spriteFuncs = ms->SpriteFuncs;
2070 }
2071
2072 if (ms->adaptor) {
2073 free(ms->adaptor);
2074 ms->adaptor = NULL;
2075 }
2076
2077 if (pScrn->vtSema) {
2078 LeaveVT(pScrn);
2079 }
2080
2081 if (ms->drmmode.exa) {
2082 PixmapPtr screen_pixmap;
2083
2084 /* Destroy exa screen pixmap before deinit exa */
2085 screen_pixmap = pScreen->GetScreenPixmap(pScreen);
2086 if (screen_pixmap == pScreen->devPrivate) {
2087 pScreen->DestroyPixmap(screen_pixmap);
2088 pScreen->devPrivate = NULL;
2089 }
2090
2091 ms_deinit_exa(pScrn);
2092 }
2093
2094 pScreen->CreateScreenResources = ms->createScreenResources;
2095 pScreen->BlockHandler = ms->BlockHandler;
2096
2097 xf86_cursors_fini(pScreen);
2098
2099 pScrn->vtSema = FALSE;
2100 pScreen->CloseScreen = ms->CloseScreen;
2101 return (*pScreen->CloseScreen) (pScreen);
2102 }
2103
2104 static ModeStatus
ValidMode(ScrnInfoPtr arg,DisplayModePtr mode,Bool verbose,int flags)2105 ValidMode(ScrnInfoPtr arg, DisplayModePtr mode, Bool verbose, int flags)
2106 {
2107 return MODE_OK;
2108 }
2109
2110 void
ms_exchange_buffers(PixmapPtr front,PixmapPtr back)2111 ms_exchange_buffers(PixmapPtr front, PixmapPtr back)
2112 {
2113 ScreenPtr screen = front->drawable.pScreen;
2114 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
2115 modesettingPtr ms = modesettingPTR(scrn);
2116
2117 #ifdef GLAMOR_HAS_GBM
2118 if (ms->drmmode.glamor)
2119 return glamor_egl_exchange_buffers(front, back);
2120 #endif
2121
2122 if (ms->drmmode.exa)
2123 return ms_exa_exchange_buffers(front, back);
2124 }
2125
2126 static Bool
ms_back_pixmap_from_fd(PixmapPtr pixmap,int fd,CARD16 width,CARD16 height,CARD16 stride,CARD8 depth,CARD8 bpp)2127 ms_back_pixmap_from_fd(PixmapPtr pixmap,
2128 int fd,
2129 CARD16 width,
2130 CARD16 height,
2131 CARD16 stride, CARD8 depth, CARD8 bpp)
2132 {
2133 ScreenPtr screen = pixmap->drawable.pScreen;
2134 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
2135 modesettingPtr ms = modesettingPTR(scrn);
2136
2137 #ifdef GLAMOR_HAS_GBM
2138 if (ms->drmmode.glamor)
2139 return glamor_back_pixmap_from_fd(pixmap, fd,
2140 width, height,
2141 stride, depth, bpp);
2142 #endif
2143
2144 if (ms->drmmode.exa)
2145 return ms_exa_back_pixmap_from_fd(pixmap, fd,
2146 width, height,
2147 stride, depth, bpp);
2148
2149 return FALSE;
2150 }
2151
2152 static int
ms_shareable_fd_from_pixmap(ScreenPtr screen,PixmapPtr pixmap,CARD16 * stride,CARD32 * size)2153 ms_shareable_fd_from_pixmap(ScreenPtr screen,
2154 PixmapPtr pixmap,
2155 CARD16 *stride,
2156 CARD32 *size)
2157 {
2158 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
2159 modesettingPtr ms = modesettingPTR(scrn);
2160
2161 #ifdef GLAMOR_HAS_GBM
2162 if (ms->drmmode.glamor)
2163 return glamor_shareable_fd_from_pixmap(screen, pixmap, stride, size);
2164 #endif
2165
2166 if (ms->drmmode.exa)
2167 return ms_exa_shareable_fd_from_pixmap(screen, pixmap, stride, size);
2168
2169 return -1;
2170 }
2171
2172 int
ms_name_from_pixmap(PixmapPtr pixmap,CARD16 * stride,CARD32 * size)2173 ms_name_from_pixmap(PixmapPtr pixmap,
2174 CARD16 *stride, CARD32 *size)
2175 {
2176 ScreenPtr screen = pixmap->drawable.pScreen;
2177 ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
2178 modesettingPtr ms = modesettingPTR(scrn);
2179 struct dumb_bo *bo;
2180
2181 #ifdef GLAMOR_HAS_GBM
2182 if (ms->drmmode.glamor)
2183 return glamor_name_from_pixmap(pixmap, stride, size);
2184 #endif
2185
2186 if (!ms->drmmode.exa)
2187 return -1;
2188
2189 bo = ms_exa_bo_from_pixmap(screen, pixmap);
2190 if (!bo)
2191 return -1;
2192
2193 *stride = bo->pitch;
2194 *size = bo->size;
2195
2196 return dumb_bo_get_name(ms->drmmode.fd, bo);
2197 }
2198