xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/drivers/modesetting/driver.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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