1 /*
2  * Copyright © 2007 Red Hat, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining a
5  * copy of this software and associated documentation files (the "Software"),
6  * to deal in the Software without restriction, including without limitation
7  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8  * and/or sell copies of the Software, and to permit persons to whom the
9  * Software is furnished to do so, subject to the following conditions:
10  *
11  * The above copyright notice and this permission notice (including the next
12  * paragraph) shall be included in all copies or substantial portions of the
13  * Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21  * SOFTWARE.
22  *
23  * Authors:
24  *    Dave Airlie <airlied@redhat.com>
25  *
26  */
27 
28 #ifdef HAVE_DIX_CONFIG_H
29 #include "dix-config.h"
30 #endif
31 
32 #include <errno.h>
33 #include <sys/ioctl.h>
34 #include <sys/mman.h>
35 #include <unistd.h>
36 #include "dumb_bo.h"
37 #include "inputstr.h"
38 #include "xf86str.h"
39 #include "X11/Xatom.h"
40 #include "mi.h"
41 #include "micmap.h"
42 #include "xf86cmap.h"
43 #include "xf86DDC.h"
44 #include <drm_fourcc.h>
45 #include <drm_mode.h>
46 
47 #include <xf86drm.h>
48 #include "xf86Crtc.h"
49 #include "drmmode_display.h"
50 #include "present.h"
51 
52 #include <cursorstr.h>
53 
54 #include <X11/extensions/dpmsconst.h>
55 
56 #include "driver.h"
57 
58 static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
59 static PixmapPtr drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
60                                               int depth, int bitsPerPixel, int devKind,
61                                               void *pPixData);
62 
63 static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob * blob)64 formats_ptr(struct drm_format_modifier_blob *blob)
65 {
66     return (uint32_t *)(((char *)blob) + blob->formats_offset);
67 }
68 
69 static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob * blob)70 modifiers_ptr(struct drm_format_modifier_blob *blob)
71 {
72     return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
73 }
74 
75 static uint32_t
get_opaque_format(uint32_t format)76 get_opaque_format(uint32_t format)
77 {
78     switch (format) {
79     case DRM_FORMAT_ARGB8888:
80         return DRM_FORMAT_XRGB8888;
81     case DRM_FORMAT_ARGB2101010:
82         return DRM_FORMAT_XRGB2101010;
83     default:
84         return format;
85     }
86 }
87 
88 Bool
drmmode_is_format_supported(ScrnInfoPtr scrn,uint32_t format,uint64_t modifier)89 drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
90 {
91     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
92     int c, i, j;
93 
94     /* BO are imported as opaque surface, so let's pretend there is no alpha */
95     format = get_opaque_format(format);
96 
97     for (c = 0; c < xf86_config->num_crtc; c++) {
98         xf86CrtcPtr crtc = xf86_config->crtc[c];
99         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
100         Bool found = FALSE;
101 
102         if (!crtc->enabled)
103             continue;
104 
105         if (drmmode_crtc->num_formats == 0)
106             continue;
107 
108         for (i = 0; i < drmmode_crtc->num_formats; i++) {
109             drmmode_format_ptr iter = &drmmode_crtc->formats[i];
110 
111             if (iter->format != format)
112                 continue;
113 
114             if (modifier == DRM_FORMAT_MOD_INVALID ||
115                 iter->num_modifiers == 0) {
116                 found = TRUE;
117                 break;
118             }
119 
120             for (j = 0; j < iter->num_modifiers; j++) {
121                 if (iter->modifiers[j] == modifier) {
122                     found = TRUE;
123                     break;
124                 }
125             }
126 
127             break;
128         }
129 
130         if (!found)
131             return FALSE;
132     }
133 
134     return TRUE;
135 }
136 
137 #ifdef GBM_BO_WITH_MODIFIERS
138 static uint32_t
get_modifiers_set(ScrnInfoPtr scrn,uint32_t format,uint64_t ** modifiers,Bool enabled_crtc_only,Bool exclude_multiplane)139 get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
140                   Bool enabled_crtc_only, Bool exclude_multiplane)
141 {
142     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
143     modesettingPtr ms = modesettingPTR(scrn);
144     drmmode_ptr drmmode = &ms->drmmode;
145     int c, i, j, k, count_modifiers = 0;
146     uint64_t *tmp, *ret = NULL;
147 
148     /* BOs are imported as opaque surfaces, so pretend the same thing here */
149     format = get_opaque_format(format);
150 
151     *modifiers = NULL;
152     for (c = 0; c < xf86_config->num_crtc; c++) {
153         xf86CrtcPtr crtc = xf86_config->crtc[c];
154         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
155 
156         if (enabled_crtc_only && !crtc->enabled)
157             continue;
158 
159         for (i = 0; i < drmmode_crtc->num_formats; i++) {
160             drmmode_format_ptr iter = &drmmode_crtc->formats[i];
161 
162             if (iter->format != format)
163                 continue;
164 
165             for (j = 0; j < iter->num_modifiers; j++) {
166                 Bool found = FALSE;
167 
168 		/* Don't choose multi-plane formats for our screen pixmap.
169 		 * These will get used with frontbuffer rendering, which will
170 		 * lead to worse-than-tearing with multi-plane formats, as the
171 		 * primary and auxiliary planes go out of sync. */
172 		if (exclude_multiplane &&
173                     gbm_device_get_format_modifier_plane_count(drmmode->gbm,
174                                                                format,
175                                                                iter->modifiers[j]) > 1) {
176                     continue;
177                 }
178 
179                 for (k = 0; k < count_modifiers; k++) {
180                     if (iter->modifiers[j] == ret[k])
181                         found = TRUE;
182                 }
183                 if (!found) {
184                     count_modifiers++;
185                     tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
186                     if (!tmp) {
187                         free(ret);
188                         return 0;
189                     }
190                     ret = tmp;
191                     ret[count_modifiers - 1] = iter->modifiers[j];
192                 }
193             }
194         }
195     }
196 
197     *modifiers = ret;
198     return count_modifiers;
199 }
200 
201 static Bool
get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)202 get_drawable_modifiers(DrawablePtr draw, uint32_t format,
203                        uint32_t *num_modifiers, uint64_t **modifiers)
204 {
205     ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
206     modesettingPtr ms = modesettingPTR(scrn);
207 
208     if (!present_can_window_flip((WindowPtr) draw) ||
209         !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
210         *num_modifiers = 0;
211         *modifiers = NULL;
212         return TRUE;
213     }
214 
215     *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
216     return TRUE;
217 }
218 #endif
219 
220 static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn,const char * s,char * output_name)221 drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
222 {
223     char **token = xstrtokenize(s, ", \t\n\r");
224     Bool ret = FALSE;
225 
226     if (!token)
227         return FALSE;
228 
229     for (int i = 0; token[i]; i++) {
230         if (strcmp(token[i], output_name) == 0)
231             ret = TRUE;
232 
233         free(token[i]);
234     }
235 
236     free(token);
237 
238     return ret;
239 }
240 
241 static uint64_t
drmmode_prop_get_value(drmmode_prop_info_ptr info,drmModeObjectPropertiesPtr props,uint64_t def)242 drmmode_prop_get_value(drmmode_prop_info_ptr info,
243                        drmModeObjectPropertiesPtr props,
244                        uint64_t def)
245 {
246     unsigned int i;
247 
248     if (info->prop_id == 0)
249         return def;
250 
251     for (i = 0; i < props->count_props; i++) {
252         unsigned int j;
253 
254         if (props->props[i] != info->prop_id)
255             continue;
256 
257         /* Simple (non-enum) types can return the value directly */
258         if (info->num_enum_values == 0)
259             return props->prop_values[i];
260 
261         /* Map from raw value to enum value */
262         for (j = 0; j < info->num_enum_values; j++) {
263             if (!info->enum_values[j].valid)
264                 continue;
265             if (info->enum_values[j].value != props->prop_values[i])
266                 continue;
267 
268             return j;
269         }
270     }
271 
272     return def;
273 }
274 
275 static uint32_t
drmmode_prop_info_update(drmmode_ptr drmmode,drmmode_prop_info_ptr info,unsigned int num_infos,drmModeObjectProperties * props)276 drmmode_prop_info_update(drmmode_ptr drmmode,
277                          drmmode_prop_info_ptr info,
278                          unsigned int num_infos,
279                          drmModeObjectProperties *props)
280 {
281     drmModePropertyRes *prop;
282     uint32_t valid_mask = 0;
283     unsigned i, j;
284 
285     assert(num_infos <= 32 && "update return type");
286 
287     for (i = 0; i < props->count_props; i++) {
288         Bool props_incomplete = FALSE;
289         unsigned int k;
290 
291         for (j = 0; j < num_infos; j++) {
292             if (info[j].prop_id == props->props[i])
293                 break;
294             if (!info[j].prop_id)
295                 props_incomplete = TRUE;
296         }
297 
298         /* We've already discovered this property. */
299         if (j != num_infos)
300             continue;
301 
302         /* We haven't found this property ID, but as we've already
303          * found all known properties, we don't need to look any
304          * further. */
305         if (!props_incomplete)
306             break;
307 
308         prop = drmModeGetProperty(drmmode->fd, props->props[i]);
309         if (!prop)
310             continue;
311 
312         for (j = 0; j < num_infos; j++) {
313             if (!strcmp(prop->name, info[j].name))
314                 break;
315         }
316 
317         /* We don't know/care about this property. */
318         if (j == num_infos) {
319             drmModeFreeProperty(prop);
320             continue;
321         }
322 
323         info[j].prop_id = props->props[i];
324         valid_mask |= 1U << j;
325 
326         if (info[j].num_enum_values == 0) {
327             drmModeFreeProperty(prop);
328             continue;
329         }
330 
331         if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
332             xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
333                        "expected property %s to be an enum,"
334                        " but it is not; ignoring\n", prop->name);
335             drmModeFreeProperty(prop);
336             continue;
337         }
338 
339         for (k = 0; k < info[j].num_enum_values; k++) {
340             int l;
341 
342             if (info[j].enum_values[k].valid)
343                 continue;
344 
345             for (l = 0; l < prop->count_enums; l++) {
346                 if (!strcmp(prop->enums[l].name,
347                             info[j].enum_values[k].name))
348                     break;
349             }
350 
351             if (l == prop->count_enums)
352                 continue;
353 
354             info[j].enum_values[k].valid = TRUE;
355             info[j].enum_values[k].value = prop->enums[l].value;
356         }
357 
358         drmModeFreeProperty(prop);
359     }
360 
361     return valid_mask;
362 }
363 
364 static Bool
drmmode_prop_info_copy(drmmode_prop_info_ptr dst,const drmmode_prop_info_rec * src,unsigned int num_props,Bool copy_prop_id)365 drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
366 		       const drmmode_prop_info_rec *src,
367 		       unsigned int num_props,
368 		       Bool copy_prop_id)
369 {
370     unsigned int i;
371 
372     memcpy(dst, src, num_props * sizeof(*dst));
373 
374     for (i = 0; i < num_props; i++) {
375         unsigned int j;
376 
377         if (copy_prop_id)
378             dst[i].prop_id = src[i].prop_id;
379         else
380             dst[i].prop_id = 0;
381 
382         if (src[i].num_enum_values == 0)
383             continue;
384 
385         dst[i].enum_values =
386             malloc(src[i].num_enum_values *
387                     sizeof(*dst[i].enum_values));
388         if (!dst[i].enum_values)
389             goto err;
390 
391         memcpy(dst[i].enum_values, src[i].enum_values,
392                 src[i].num_enum_values * sizeof(*dst[i].enum_values));
393 
394         for (j = 0; j < dst[i].num_enum_values; j++)
395             dst[i].enum_values[j].valid = FALSE;
396     }
397 
398     return TRUE;
399 
400 err:
401     while (i--)
402         free(dst[i].enum_values);
403     return FALSE;
404 }
405 
406 static void
drmmode_prop_info_free(drmmode_prop_info_ptr info,int num_props)407 drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
408 {
409     int i;
410 
411     for (i = 0; i < num_props; i++)
412         free(info[i].enum_values);
413 }
414 
415 static void
416 drmmode_ConvertToKMode(ScrnInfoPtr scrn,
417                        drmModeModeInfo * kmode, DisplayModePtr mode);
418 
419 
420 static int
plane_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_plane_property prop,uint64_t val)421 plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
422                enum drmmode_plane_property prop, uint64_t val)
423 {
424     drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
425     int ret;
426 
427     if (!info)
428         return -1;
429 
430     ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
431                                    info->prop_id, val);
432     return (ret <= 0) ? -1 : 0;
433 }
434 
435 static int
plane_add_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,uint32_t fb_id,int x,int y)436 plane_add_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
437                 uint32_t fb_id, int x, int y)
438 {
439     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
440     int ret = 0;
441 
442     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
443                           fb_id);
444     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
445                           fb_id ? drmmode_crtc->mode_crtc->crtc_id : 0);
446     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
447     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
448     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
449                           crtc->mode.HDisplay << 16);
450     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
451                           crtc->mode.VDisplay << 16);
452     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
453     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
454     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
455                           crtc->mode.HDisplay);
456     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
457                           crtc->mode.VDisplay);
458 
459     return ret;
460 }
461 
462 static int
crtc_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_crtc_property prop,uint64_t val)463 crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
464               enum drmmode_crtc_property prop, uint64_t val)
465 {
466     drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
467     int ret;
468 
469     if (!info)
470         return -1;
471 
472     ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
473                                    info->prop_id, val);
474     return (ret <= 0) ? -1 : 0;
475 }
476 
477 static int
connector_add_prop(drmModeAtomicReq * req,drmmode_output_private_ptr drmmode_output,enum drmmode_connector_property prop,uint64_t val)478 connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
479                    enum drmmode_connector_property prop, uint64_t val)
480 {
481     drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
482     int ret;
483 
484     if (!info)
485         return -1;
486 
487     ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
488                                    info->prop_id, val);
489     return (ret <= 0) ? -1 : 0;
490 }
491 
492 static int
drmmode_CompareKModes(drmModeModeInfo * kmode,drmModeModeInfo * other)493 drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
494 {
495     return memcmp(kmode, other, sizeof(*kmode));
496 }
497 
498 static int
drm_mode_ensure_blob(xf86CrtcPtr crtc,drmModeModeInfo mode_info)499 drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
500 {
501     modesettingPtr ms = modesettingPTR(crtc->scrn);
502     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
503     drmmode_mode_ptr mode;
504     int ret;
505 
506     if (drmmode_crtc->current_mode &&
507         drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
508         return 0;
509 
510     mode = calloc(sizeof(drmmode_mode_rec), 1);
511     if (!mode)
512         return -1;
513 
514     mode->mode_info = mode_info;
515     ret = drmModeCreatePropertyBlob(ms->fd,
516                                     &mode->mode_info,
517                                     sizeof(mode->mode_info),
518                                     &mode->blob_id);
519     drmmode_crtc->current_mode = mode;
520     xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
521 
522     return ret;
523 }
524 
525 static int
crtc_add_dpms_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,int new_dpms,Bool * active)526 crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
527                     int new_dpms, Bool *active)
528 {
529     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
530     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
531     Bool crtc_active = FALSE;
532     int i;
533     int ret = 0;
534 
535     for (i = 0; i < xf86_config->num_output; i++) {
536         xf86OutputPtr output = xf86_config->output[i];
537         drmmode_output_private_ptr drmmode_output = output->driver_private;
538 
539         if (output->crtc != crtc) {
540             if (drmmode_output->current_crtc == crtc) {
541                 ret |= connector_add_prop(req, drmmode_output,
542                                           DRMMODE_CONNECTOR_CRTC_ID, 0);
543             }
544             continue;
545         }
546 
547         if (drmmode_output->output_id == -1)
548             continue;
549 
550         if (new_dpms == DPMSModeOn)
551             crtc_active = TRUE;
552 
553         ret |= connector_add_prop(req, drmmode_output,
554                                   DRMMODE_CONNECTOR_CRTC_ID,
555                                   crtc_active ?
556                                       drmmode_crtc->mode_crtc->crtc_id : 0);
557     }
558 
559     if (crtc_active) {
560         drmModeModeInfo kmode;
561 
562         drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
563         ret |= drm_mode_ensure_blob(crtc, kmode);
564 
565         ret |= crtc_add_prop(req, drmmode_crtc,
566                              DRMMODE_CRTC_ACTIVE, 1);
567         ret |= crtc_add_prop(req, drmmode_crtc,
568                              DRMMODE_CRTC_MODE_ID,
569                              drmmode_crtc->current_mode->blob_id);
570     } else {
571         ret |= crtc_add_prop(req, drmmode_crtc,
572                              DRMMODE_CRTC_ACTIVE, 0);
573         ret |= crtc_add_prop(req, drmmode_crtc,
574                              DRMMODE_CRTC_MODE_ID, 0);
575     }
576 
577     if (active)
578         *active = crtc_active;
579 
580     return ret;
581 }
582 
583 static void
drm_mode_destroy(xf86CrtcPtr crtc,drmmode_mode_ptr mode)584 drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
585 {
586     modesettingPtr ms = modesettingPTR(crtc->scrn);
587     if (mode->blob_id)
588         drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
589     xorg_list_del(&mode->entry);
590     free(mode);
591 }
592 
593 static int
drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)594 drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
595 {
596     modesettingPtr ms = modesettingPTR(crtc->scrn);
597 
598     return ms->atomic_modeset;
599 }
600 
601 static Bool
drmmode_crtc_get_fb_id(xf86CrtcPtr crtc,uint32_t * fb_id,int * x,int * y)602 drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
603 {
604     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
605     drmmode_ptr drmmode = drmmode_crtc->drmmode;
606     int ret;
607 
608     *fb_id = 0;
609 
610     if (drmmode_crtc->prime_pixmap) {
611         if (!drmmode->reverse_prime_offload_mode) {
612             msPixmapPrivPtr ppriv =
613                 msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
614             *fb_id = ppriv->fb_id;
615             *x = 0;
616         } else
617             *x = drmmode_crtc->prime_pixmap_x;
618         *y = 0;
619     }
620     else if (drmmode_crtc->rotate_fb_id) {
621         *fb_id = drmmode_crtc->rotate_fb_id;
622         *x = *y = 0;
623     }
624     else {
625         *fb_id = drmmode->fb_id;
626         *x = crtc->x;
627         *y = crtc->y;
628     }
629 
630     if (*fb_id == 0) {
631         ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
632                                 &drmmode->fb_id);
633         if (ret < 0) {
634             ErrorF("failed to add fb %d\n", ret);
635             return FALSE;
636         }
637         *fb_id = drmmode->fb_id;
638     }
639 
640     return TRUE;
641 }
642 
643 void
drmmode_set_dpms(ScrnInfoPtr scrn,int dpms,int flags)644 drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
645 {
646     modesettingPtr ms = modesettingPTR(scrn);
647     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
648     drmModeAtomicReq *req = drmModeAtomicAlloc();
649     uint32_t mode_flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
650     int ret = 0;
651     int i;
652 
653     assert(ms->atomic_modeset);
654 
655     if (!req)
656         return;
657 
658     for (i = 0; i < xf86_config->num_output; i++) {
659         xf86OutputPtr output = xf86_config->output[i];
660         drmmode_output_private_ptr drmmode_output = output->driver_private;
661 
662         if (output->crtc != NULL)
663             continue;
664 
665         ret = connector_add_prop(req, drmmode_output,
666                                  DRMMODE_CONNECTOR_CRTC_ID, 0);
667     }
668 
669     for (i = 0; i < xf86_config->num_crtc; i++) {
670         xf86CrtcPtr crtc = xf86_config->crtc[i];
671         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
672         Bool active = FALSE;
673 
674         ret |= crtc_add_dpms_props(req, crtc, dpms, &active);
675 
676         if (dpms == DPMSModeOn && active && drmmode_crtc->need_modeset) {
677             uint32_t fb_id;
678             int x, y;
679 
680             if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
681                 continue;
682             ret |= plane_add_props(req, crtc, fb_id, x, y);
683             drmmode_crtc->need_modeset = FALSE;
684         }
685     }
686 
687     if (ret == 0)
688         drmModeAtomicCommit(ms->fd, req, mode_flags, NULL);
689     drmModeAtomicFree(req);
690 
691     ms->pending_modeset = TRUE;
692     xf86DPMSSet(scrn, dpms, flags);
693     ms->pending_modeset = FALSE;
694 }
695 
696 static int
drmmode_output_disable(xf86OutputPtr output)697 drmmode_output_disable(xf86OutputPtr output)
698 {
699     modesettingPtr ms = modesettingPTR(output->scrn);
700     drmmode_output_private_ptr drmmode_output = output->driver_private;
701     xf86CrtcPtr crtc = drmmode_output->current_crtc;
702     drmModeAtomicReq *req = drmModeAtomicAlloc();
703     uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
704     int ret = 0;
705 
706     assert(ms->atomic_modeset);
707 
708     if (!req)
709         return 1;
710 
711     ret |= connector_add_prop(req, drmmode_output,
712                               DRMMODE_CONNECTOR_CRTC_ID, 0);
713     if (crtc)
714         ret |= crtc_add_dpms_props(req, crtc, DPMSModeOff, NULL);
715 
716     if (ret == 0)
717         ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
718 
719     if (ret == 0)
720         drmmode_output->current_crtc = NULL;
721 
722     drmModeAtomicFree(req);
723     return ret;
724 }
725 
726 static int
drmmode_crtc_disable(xf86CrtcPtr crtc)727 drmmode_crtc_disable(xf86CrtcPtr crtc)
728 {
729     modesettingPtr ms = modesettingPTR(crtc->scrn);
730     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
731     drmModeAtomicReq *req = drmModeAtomicAlloc();
732     uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
733     int ret = 0;
734 
735     assert(ms->atomic_modeset);
736 
737     if (!req)
738         return 1;
739 
740     ret |= crtc_add_prop(req, drmmode_crtc,
741                          DRMMODE_CRTC_ACTIVE, 0);
742     ret |= crtc_add_prop(req, drmmode_crtc,
743                          DRMMODE_CRTC_MODE_ID, 0);
744 
745     if (ret == 0)
746         ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
747 
748     drmModeAtomicFree(req);
749     return ret;
750 }
751 
752 static int
drmmode_crtc_set_mode(xf86CrtcPtr crtc,Bool test_only)753 drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
754 {
755     modesettingPtr ms = modesettingPTR(crtc->scrn);
756     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
757     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
758     drmmode_ptr drmmode = drmmode_crtc->drmmode;
759     ScreenPtr screen = crtc->scrn->pScreen;
760     drmModeModeInfo kmode;
761     int output_count = 0;
762     uint32_t *output_ids = NULL;
763     uint32_t fb_id;
764     int x, y;
765     int i, ret = 0;
766 
767     if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
768         return 1;
769 
770 #ifdef GLAMOR_HAS_GBM
771     /* Make sure any pending drawing will be visible in a new scanout buffer */
772     if (drmmode->glamor)
773         glamor_finish(screen);
774 #endif
775 
776     if (ms->atomic_modeset) {
777         drmModeAtomicReq *req = drmModeAtomicAlloc();
778         Bool active;
779         uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
780 
781         if (!req)
782             return 1;
783 
784         ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
785         ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
786 
787         /* Orphaned CRTCs need to be disabled right now in atomic mode */
788         for (i = 0; i < xf86_config->num_crtc; i++) {
789             xf86CrtcPtr other_crtc = xf86_config->crtc[i];
790             drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
791             int lost_outputs = 0;
792             int remaining_outputs = 0;
793             int j;
794 
795             if (other_crtc == crtc)
796                 continue;
797 
798             for (j = 0; j < xf86_config->num_output; j++) {
799                 xf86OutputPtr output = xf86_config->output[j];
800                 drmmode_output_private_ptr drmmode_output = output->driver_private;
801 
802                 if (drmmode_output->current_crtc == other_crtc) {
803                     if (output->crtc == crtc)
804                         lost_outputs++;
805                     else
806                         remaining_outputs++;
807                 }
808             }
809 
810             if (lost_outputs > 0 && remaining_outputs == 0) {
811                 ret |= crtc_add_prop(req, other_drmmode_crtc,
812                                      DRMMODE_CRTC_ACTIVE, 0);
813                 ret |= crtc_add_prop(req, other_drmmode_crtc,
814                                      DRMMODE_CRTC_MODE_ID, 0);
815             }
816         }
817 
818         if (test_only)
819             flags |= DRM_MODE_ATOMIC_TEST_ONLY;
820 
821         if (ret == 0)
822             ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
823 
824         if (ret == 0 && !test_only) {
825             for (i = 0; i < xf86_config->num_output; i++) {
826                 xf86OutputPtr output = xf86_config->output[i];
827                 drmmode_output_private_ptr drmmode_output = output->driver_private;
828 
829                 if (output->crtc == crtc)
830                     drmmode_output->current_crtc = crtc;
831                 else if (drmmode_output->current_crtc == crtc)
832                     drmmode_output->current_crtc = NULL;
833             }
834         }
835 
836         drmModeAtomicFree(req);
837         return ret;
838     }
839 
840     output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
841     if (!output_ids)
842         return -1;
843 
844     for (i = 0; i < xf86_config->num_output; i++) {
845         xf86OutputPtr output = xf86_config->output[i];
846         drmmode_output_private_ptr drmmode_output;
847 
848         if (output->crtc != crtc)
849             continue;
850 
851         drmmode_output = output->driver_private;
852         if (drmmode_output->output_id == -1)
853             continue;
854         output_ids[output_count] = drmmode_output->output_id;
855         output_count++;
856     }
857 
858     drmmode_ConvertToKMode(crtc->scrn, &kmode, &crtc->mode);
859     ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
860                          fb_id, x, y, output_ids, output_count, &kmode);
861 
862     free(output_ids);
863     return ret;
864 }
865 
866 int
drmmode_crtc_flip(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t flags,void * data)867 drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
868 {
869     modesettingPtr ms = modesettingPTR(crtc->scrn);
870     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
871     int ret;
872 
873     if (ms->atomic_modeset) {
874         drmModeAtomicReq *req = drmModeAtomicAlloc();
875 
876         if (!req)
877             return 1;
878 
879         ret = plane_add_props(req, crtc, fb_id, crtc->x, crtc->y);
880         flags |= DRM_MODE_ATOMIC_NONBLOCK;
881         if (ret == 0)
882             ret = drmModeAtomicCommit(ms->fd, req, flags, data);
883         drmModeAtomicFree(req);
884         return ret;
885     }
886 
887     return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
888                            fb_id, flags, data);
889 }
890 
891 int
drmmode_bo_destroy(drmmode_ptr drmmode,drmmode_bo * bo)892 drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
893 {
894     int ret;
895 
896 #ifdef GLAMOR_HAS_GBM
897     if (bo->gbm) {
898         gbm_bo_destroy(bo->gbm);
899         bo->gbm = NULL;
900     }
901 #endif
902 
903     if (bo->dumb) {
904         ret = dumb_bo_destroy(drmmode->fd, bo->dumb);
905         if (ret == 0)
906             bo->dumb = NULL;
907     }
908 
909     return 0;
910 }
911 
912 uint32_t
drmmode_bo_get_pitch(drmmode_bo * bo)913 drmmode_bo_get_pitch(drmmode_bo *bo)
914 {
915 #ifdef GLAMOR_HAS_GBM
916     if (bo->gbm)
917         return gbm_bo_get_stride(bo->gbm);
918 #endif
919 
920     return bo->dumb->pitch;
921 }
922 
923 static Bool
drmmode_bo_has_bo(drmmode_bo * bo)924 drmmode_bo_has_bo(drmmode_bo *bo)
925 {
926 #ifdef GLAMOR_HAS_GBM
927     if (bo->gbm)
928         return TRUE;
929 #endif
930 
931     return bo->dumb != NULL;
932 }
933 
934 uint32_t
drmmode_bo_get_handle(drmmode_bo * bo)935 drmmode_bo_get_handle(drmmode_bo *bo)
936 {
937 #ifdef GLAMOR_HAS_GBM
938     if (bo->gbm)
939         return gbm_bo_get_handle(bo->gbm).u32;
940 #endif
941 
942     return bo->dumb->handle;
943 }
944 
945 static void *
drmmode_bo_map(drmmode_ptr drmmode,drmmode_bo * bo)946 drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
947 {
948     int ret;
949 
950 #ifdef GLAMOR_HAS_GBM
951     if (bo->gbm)
952         return NULL;
953 #endif
954 
955     if (bo->dumb->ptr)
956         return bo->dumb->ptr;
957 
958     ret = dumb_bo_map(drmmode->fd, bo->dumb);
959     if (ret)
960         return NULL;
961 
962     return bo->dumb->ptr;
963 }
964 
965 int
drmmode_bo_import(drmmode_ptr drmmode,drmmode_bo * bo,uint32_t * fb_id)966 drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
967                   uint32_t *fb_id)
968 {
969 #ifdef GBM_BO_WITH_MODIFIERS
970     modesettingPtr ms = modesettingPTR(drmmode->scrn);
971     if (bo->gbm && ms->kms_has_modifiers &&
972         gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
973         int num_fds;
974 
975         num_fds = gbm_bo_get_plane_count(bo->gbm);
976         if (num_fds > 0) {
977             int i;
978             uint32_t format;
979             uint32_t handles[4];
980             uint32_t strides[4];
981             uint32_t offsets[4];
982             uint64_t modifiers[4];
983 
984             memset(handles, 0, sizeof(handles));
985             memset(strides, 0, sizeof(strides));
986             memset(offsets, 0, sizeof(offsets));
987             memset(modifiers, 0, sizeof(modifiers));
988 
989             format = gbm_bo_get_format(bo->gbm);
990             format = get_opaque_format(format);
991             for (i = 0; i < num_fds; i++) {
992                 handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
993                 strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
994                 offsets[i] = gbm_bo_get_offset(bo->gbm, i);
995                 modifiers[i] = gbm_bo_get_modifier(bo->gbm);
996             }
997 
998             return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
999                                               format, handles, strides,
1000                                               offsets, modifiers, fb_id,
1001                                               DRM_MODE_FB_MODIFIERS);
1002         }
1003     }
1004 #endif
1005     return drmModeAddFB(drmmode->fd, bo->width, bo->height,
1006                         drmmode->scrn->depth, drmmode->kbpp,
1007                         drmmode_bo_get_pitch(bo),
1008                         drmmode_bo_get_handle(bo), fb_id);
1009 }
1010 
1011 static Bool
drmmode_create_bo(drmmode_ptr drmmode,drmmode_bo * bo,unsigned width,unsigned height,unsigned bpp)1012 drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
1013                   unsigned width, unsigned height, unsigned bpp)
1014 {
1015     bo->width = width;
1016     bo->height = height;
1017 
1018 #ifdef GLAMOR_HAS_GBM
1019     if (drmmode->glamor) {
1020         uint32_t format;
1021 
1022         if (drmmode->scrn->depth == 30)
1023             format = GBM_FORMAT_ARGB2101010;
1024         else
1025             format = GBM_FORMAT_ARGB8888;
1026 
1027 #ifdef GBM_BO_WITH_MODIFIERS
1028         uint32_t num_modifiers;
1029         uint64_t *modifiers = NULL;
1030 
1031         num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
1032                                           FALSE, TRUE);
1033         if (num_modifiers > 0 &&
1034             !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
1035             bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
1036                                                    format, modifiers,
1037                                                    num_modifiers);
1038             free(modifiers);
1039             if (bo->gbm) {
1040                 bo->used_modifiers = TRUE;
1041                 return TRUE;
1042             }
1043         }
1044 #endif
1045 
1046         bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
1047                                 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
1048         bo->used_modifiers = FALSE;
1049         return bo->gbm != NULL;
1050     }
1051 #endif
1052 
1053     bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp);
1054     return bo->dumb != NULL;
1055 }
1056 
1057 Bool
drmmode_SetSlaveBO(PixmapPtr ppix,drmmode_ptr drmmode,int fd_handle,int pitch,int size)1058 drmmode_SetSlaveBO(PixmapPtr ppix,
1059                    drmmode_ptr drmmode, int fd_handle, int pitch, int size)
1060 {
1061     msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1062 
1063     if (fd_handle == -1) {
1064         dumb_bo_destroy(drmmode->fd, ppriv->backing_bo);
1065         ppriv->backing_bo = NULL;
1066         return TRUE;
1067     }
1068 
1069     ppriv->backing_bo =
1070         dumb_get_bo_from_fd(drmmode->fd, fd_handle, pitch, size);
1071     if (!ppriv->backing_bo)
1072         return FALSE;
1073 
1074     close(fd_handle);
1075     return TRUE;
1076 }
1077 
1078 static Bool
drmmode_SharedPixmapPresent(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1079 drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
1080                             drmmode_ptr drmmode)
1081 {
1082     ScreenPtr master = crtc->randr_crtc->pScreen->current_master;
1083 
1084     if (master->PresentSharedPixmap(ppix)) {
1085         /* Success, queue flip to back target */
1086         if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
1087             return TRUE;
1088 
1089         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
1090                    "drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
1091 
1092         return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1093     }
1094 
1095     /* Failed to present, try again on next vblank after damage */
1096     if (master->RequestSharedPixmapNotifyDamage) {
1097         msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1098 
1099         /* Set flag first in case we are immediately notified */
1100         ppriv->wait_for_damage = TRUE;
1101 
1102         if (master->RequestSharedPixmapNotifyDamage(ppix))
1103             return TRUE;
1104         else
1105             ppriv->wait_for_damage = FALSE;
1106     }
1107 
1108     /* Damage notification not available, just try again on vblank */
1109     return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1110 }
1111 
1112 struct vblank_event_args {
1113     PixmapPtr frontTarget;
1114     PixmapPtr backTarget;
1115     xf86CrtcPtr crtc;
1116     drmmode_ptr drmmode;
1117     Bool flip;
1118 };
1119 static void
drmmode_SharedPixmapVBlankEventHandler(uint64_t frame,uint64_t usec,void * data)1120 drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
1121                                        void *data)
1122 {
1123     struct vblank_event_args *args = data;
1124 
1125     drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
1126 
1127     if (args->flip) {
1128         /* frontTarget is being displayed, update crtc to reflect */
1129         drmmode_crtc->prime_pixmap = args->frontTarget;
1130         drmmode_crtc->prime_pixmap_back = args->backTarget;
1131 
1132         /* Safe to present on backTarget, no longer displayed */
1133         drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
1134     } else {
1135         /* backTarget is still being displayed, present on frontTarget */
1136         drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
1137     }
1138 
1139     free(args);
1140 }
1141 
1142 static void
drmmode_SharedPixmapVBlankEventAbort(void * data)1143 drmmode_SharedPixmapVBlankEventAbort(void *data)
1144 {
1145     struct vblank_event_args *args = data;
1146 
1147     msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
1148 
1149     free(args);
1150 }
1151 
1152 Bool
drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1153 drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
1154                                     drmmode_ptr drmmode)
1155 {
1156     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1157     msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1158     struct vblank_event_args *event_args;
1159 
1160     if (ppix == drmmode_crtc->prime_pixmap)
1161         return FALSE; /* Already flipped to this pixmap */
1162     if (ppix != drmmode_crtc->prime_pixmap_back)
1163         return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
1164 
1165     event_args = calloc(1, sizeof(*event_args));
1166     if (!event_args)
1167         return FALSE;
1168 
1169     event_args->frontTarget = ppix;
1170     event_args->backTarget = drmmode_crtc->prime_pixmap;
1171     event_args->crtc = crtc;
1172     event_args->drmmode = drmmode;
1173     event_args->flip = FALSE;
1174 
1175     ppriv->flip_seq =
1176         ms_drm_queue_alloc(crtc, event_args,
1177                            drmmode_SharedPixmapVBlankEventHandler,
1178                            drmmode_SharedPixmapVBlankEventAbort);
1179 
1180     return ms_queue_vblank(crtc, MS_QUEUE_RELATIVE, 1, NULL, ppriv->flip_seq);
1181 }
1182 
1183 Bool
drmmode_SharedPixmapFlip(PixmapPtr frontTarget,xf86CrtcPtr crtc,drmmode_ptr drmmode)1184 drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
1185                          drmmode_ptr drmmode)
1186 {
1187     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1188     msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
1189 
1190     struct vblank_event_args *event_args;
1191 
1192     event_args = calloc(1, sizeof(*event_args));
1193     if (!event_args)
1194         return FALSE;
1195 
1196     event_args->frontTarget = frontTarget;
1197     event_args->backTarget = drmmode_crtc->prime_pixmap;
1198     event_args->crtc = crtc;
1199     event_args->drmmode = drmmode;
1200     event_args->flip = TRUE;
1201 
1202     ppriv_front->flip_seq =
1203         ms_drm_queue_alloc(crtc, event_args,
1204                            drmmode_SharedPixmapVBlankEventHandler,
1205                            drmmode_SharedPixmapVBlankEventAbort);
1206 
1207     if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1208                         ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1209                         (void *)(intptr_t) ppriv_front->flip_seq) < 0) {
1210         ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
1211         return FALSE;
1212     }
1213 
1214     return TRUE;
1215 }
1216 
1217 static Bool
drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1218 drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1219 {
1220     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1221 
1222     if (!drmmode_crtc->enable_flipping)
1223         return FALSE;
1224 
1225     if (drmmode_crtc->flipping_active)
1226         return TRUE;
1227 
1228     drmmode_crtc->flipping_active =
1229         drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
1230                                     crtc, drmmode);
1231 
1232     return drmmode_crtc->flipping_active;
1233 }
1234 
1235 static void
drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1236 drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1237 {
1238     uint32_t seq;
1239     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1240 
1241     if (!drmmode_crtc->flipping_active)
1242         return;
1243 
1244     drmmode_crtc->flipping_active = FALSE;
1245 
1246     /* Abort page flip event handler on prime_pixmap */
1247     seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
1248     if (seq)
1249         ms_drm_abort_seq(crtc->scrn, seq);
1250 
1251     /* Abort page flip event handler on prime_pixmap_back */
1252     seq = msGetPixmapPriv(drmmode,
1253                           drmmode_crtc->prime_pixmap_back)->flip_seq;
1254     if (seq)
1255         ms_drm_abort_seq(crtc->scrn, seq);
1256 }
1257 
1258 static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1259                                               PixmapPtr *target);
1260 
1261 Bool
drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode,PixmapPtr front,PixmapPtr back)1262 drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
1263                                    PixmapPtr front, PixmapPtr back)
1264 {
1265     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1266 
1267     drmmode_crtc->enable_flipping = TRUE;
1268 
1269     /* Set front scanout pixmap */
1270     drmmode_crtc->enable_flipping &=
1271         drmmode_set_target_scanout_pixmap(crtc, front,
1272                                           &drmmode_crtc->prime_pixmap);
1273     if (!drmmode_crtc->enable_flipping)
1274         return FALSE;
1275 
1276     /* Set back scanout pixmap */
1277     drmmode_crtc->enable_flipping &=
1278         drmmode_set_target_scanout_pixmap(crtc, back,
1279                                           &drmmode_crtc->prime_pixmap_back);
1280     if (!drmmode_crtc->enable_flipping) {
1281         drmmode_set_target_scanout_pixmap(crtc, NULL,
1282                                           &drmmode_crtc->prime_pixmap);
1283         return FALSE;
1284     }
1285 
1286     return TRUE;
1287 }
1288 
1289 void
drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1290 drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1291 {
1292     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1293 
1294     drmmode_crtc->enable_flipping = FALSE;
1295 
1296     drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
1297 
1298     drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
1299 
1300     drmmode_set_target_scanout_pixmap(crtc, NULL,
1301                                       &drmmode_crtc->prime_pixmap_back);
1302 }
1303 
1304 static void
drmmode_ConvertFromKMode(ScrnInfoPtr scrn,drmModeModeInfo * kmode,DisplayModePtr mode)1305 drmmode_ConvertFromKMode(ScrnInfoPtr scrn,
1306                          drmModeModeInfo * kmode, DisplayModePtr mode)
1307 {
1308     memset(mode, 0, sizeof(DisplayModeRec));
1309     mode->status = MODE_OK;
1310 
1311     mode->Clock = kmode->clock;
1312 
1313     mode->HDisplay = kmode->hdisplay;
1314     mode->HSyncStart = kmode->hsync_start;
1315     mode->HSyncEnd = kmode->hsync_end;
1316     mode->HTotal = kmode->htotal;
1317     mode->HSkew = kmode->hskew;
1318 
1319     mode->VDisplay = kmode->vdisplay;
1320     mode->VSyncStart = kmode->vsync_start;
1321     mode->VSyncEnd = kmode->vsync_end;
1322     mode->VTotal = kmode->vtotal;
1323     mode->VScan = kmode->vscan;
1324 
1325     mode->Flags = kmode->flags; //& FLAG_BITS;
1326     mode->name = strdup(kmode->name);
1327 
1328     if (kmode->type & DRM_MODE_TYPE_DRIVER)
1329         mode->type = M_T_DRIVER;
1330     if (kmode->type & DRM_MODE_TYPE_PREFERRED)
1331         mode->type |= M_T_PREFERRED;
1332     xf86SetModeCrtc(mode, scrn->adjustFlags);
1333 }
1334 
1335 static void
drmmode_ConvertToKMode(ScrnInfoPtr scrn,drmModeModeInfo * kmode,DisplayModePtr mode)1336 drmmode_ConvertToKMode(ScrnInfoPtr scrn,
1337                        drmModeModeInfo * kmode, DisplayModePtr mode)
1338 {
1339     memset(kmode, 0, sizeof(*kmode));
1340 
1341     kmode->clock = mode->Clock;
1342     kmode->hdisplay = mode->HDisplay;
1343     kmode->hsync_start = mode->HSyncStart;
1344     kmode->hsync_end = mode->HSyncEnd;
1345     kmode->htotal = mode->HTotal;
1346     kmode->hskew = mode->HSkew;
1347 
1348     kmode->vdisplay = mode->VDisplay;
1349     kmode->vsync_start = mode->VSyncStart;
1350     kmode->vsync_end = mode->VSyncEnd;
1351     kmode->vtotal = mode->VTotal;
1352     kmode->vscan = mode->VScan;
1353 
1354     kmode->flags = mode->Flags; //& FLAG_BITS;
1355     if (mode->name)
1356         strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
1357     kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
1358 
1359 }
1360 
1361 static void
drmmode_crtc_dpms(xf86CrtcPtr crtc,int mode)1362 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
1363 {
1364     modesettingPtr ms = modesettingPTR(crtc->scrn);
1365     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1366     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1367 
1368     /* XXX Check if DPMS mode is already the right one */
1369 
1370     drmmode_crtc->dpms_mode = mode;
1371 
1372     if (ms->atomic_modeset) {
1373         if (mode != DPMSModeOn && !ms->pending_modeset)
1374             drmmode_crtc_disable(crtc);
1375     } else if (crtc->enabled == FALSE) {
1376         drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1377                        0, 0, 0, NULL, 0, NULL);
1378     }
1379 }
1380 
1381 #ifdef GLAMOR_HAS_GBM
1382 static PixmapPtr
create_pixmap_for_fbcon(drmmode_ptr drmmode,ScrnInfoPtr pScrn,int fbcon_id)1383 create_pixmap_for_fbcon(drmmode_ptr drmmode, ScrnInfoPtr pScrn, int fbcon_id)
1384 {
1385     PixmapPtr pixmap = drmmode->fbcon_pixmap;
1386     drmModeFBPtr fbcon;
1387     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1388     Bool ret;
1389 
1390     if (pixmap)
1391         return pixmap;
1392 
1393     fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
1394     if (fbcon == NULL)
1395         return NULL;
1396 
1397     if (fbcon->depth != pScrn->depth ||
1398         fbcon->width != pScrn->virtualX ||
1399         fbcon->height != pScrn->virtualY)
1400         goto out_free_fb;
1401 
1402     pixmap = drmmode_create_pixmap_header(pScreen, fbcon->width,
1403                                           fbcon->height, fbcon->depth,
1404                                           fbcon->bpp, fbcon->pitch, NULL);
1405     if (!pixmap)
1406         goto out_free_fb;
1407 
1408     ret = glamor_egl_create_textured_pixmap(pixmap, fbcon->handle, fbcon->pitch);
1409     if (!ret) {
1410       FreePixmap(pixmap);
1411       pixmap = NULL;
1412     }
1413 
1414     drmmode->fbcon_pixmap = pixmap;
1415 out_free_fb:
1416     drmModeFreeFB(fbcon);
1417     return pixmap;
1418 }
1419 #endif
1420 
1421 void
drmmode_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode)1422 drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1423 {
1424 #ifdef GLAMOR_HAS_GBM
1425     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1426     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1427     PixmapPtr src, dst;
1428     int fbcon_id = 0;
1429     GCPtr gc;
1430     int i;
1431 
1432     for (i = 0; i < xf86_config->num_crtc; i++) {
1433         drmmode_crtc_private_ptr drmmode_crtc = xf86_config->crtc[i]->driver_private;
1434         if (drmmode_crtc->mode_crtc->buffer_id)
1435             fbcon_id = drmmode_crtc->mode_crtc->buffer_id;
1436     }
1437 
1438     if (!fbcon_id)
1439         return;
1440 
1441     if (fbcon_id == drmmode->fb_id) {
1442         /* in some rare case there might be no fbcon and we might already
1443          * be the one with the current fb to avoid a false deadlck in
1444          * kernel ttm code just do nothing as anyway there is nothing
1445          * to do
1446          */
1447         return;
1448     }
1449 
1450     src = create_pixmap_for_fbcon(drmmode, pScrn, fbcon_id);
1451     if (!src)
1452         return;
1453 
1454     dst = pScreen->GetScreenPixmap(pScreen);
1455 
1456     gc = GetScratchGC(pScrn->depth, pScreen);
1457     ValidateGC(&dst->drawable, gc);
1458 
1459     (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, 0, 0,
1460                          pScrn->virtualX, pScrn->virtualY, 0, 0);
1461 
1462     FreeScratchGC(gc);
1463 
1464     pScreen->canDoBGNoneRoot = TRUE;
1465 
1466     if (drmmode->fbcon_pixmap)
1467         pScrn->pScreen->DestroyPixmap(drmmode->fbcon_pixmap);
1468     drmmode->fbcon_pixmap = NULL;
1469 #endif
1470 }
1471 
1472 static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)1473 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
1474                        Rotation rotation, int x, int y)
1475 {
1476     modesettingPtr ms = modesettingPTR(crtc->scrn);
1477     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1478     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1479     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1480     int saved_x, saved_y;
1481     Rotation saved_rotation;
1482     DisplayModeRec saved_mode;
1483     Bool ret = TRUE;
1484     Bool can_test;
1485     int i;
1486 
1487     saved_mode = crtc->mode;
1488     saved_x = crtc->x;
1489     saved_y = crtc->y;
1490     saved_rotation = crtc->rotation;
1491 
1492     if (mode) {
1493         crtc->mode = *mode;
1494         crtc->x = x;
1495         crtc->y = y;
1496         crtc->rotation = rotation;
1497 
1498         if (!xf86CrtcRotate(crtc)) {
1499             goto done;
1500         }
1501 
1502         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1503                                crtc->gamma_blue, crtc->gamma_size);
1504 
1505         can_test = drmmode_crtc_can_test_mode(crtc);
1506         if (drmmode_crtc_set_mode(crtc, can_test)) {
1507             xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1508                        "failed to set mode: %s\n", strerror(errno));
1509             ret = FALSE;
1510             goto done;
1511         } else
1512             ret = TRUE;
1513 
1514         if (crtc->scrn->pScreen)
1515             xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
1516 
1517         ms->pending_modeset = TRUE;
1518         drmmode_crtc->need_modeset = FALSE;
1519         crtc->funcs->dpms(crtc, DPMSModeOn);
1520 
1521         if (drmmode_crtc->prime_pixmap_back)
1522             drmmode_InitSharedPixmapFlipping(crtc, drmmode);
1523 
1524         /* go through all the outputs and force DPMS them back on? */
1525         for (i = 0; i < xf86_config->num_output; i++) {
1526             xf86OutputPtr output = xf86_config->output[i];
1527             drmmode_output_private_ptr drmmode_output;
1528 
1529             if (output->crtc != crtc)
1530                 continue;
1531 
1532             drmmode_output = output->driver_private;
1533             if (drmmode_output->output_id == -1)
1534                 continue;
1535             output->funcs->dpms(output, DPMSModeOn);
1536         }
1537 
1538         /* if we only tested the mode previously, really set it now */
1539         if (can_test)
1540             drmmode_crtc_set_mode(crtc, FALSE);
1541         ms->pending_modeset = FALSE;
1542     }
1543 
1544  done:
1545     if (!ret) {
1546         crtc->x = saved_x;
1547         crtc->y = saved_y;
1548         crtc->rotation = saved_rotation;
1549         crtc->mode = saved_mode;
1550     } else
1551         crtc->active = TRUE;
1552 
1553     return ret;
1554 }
1555 
1556 static void
drmmode_set_cursor_colors(xf86CrtcPtr crtc,int bg,int fg)1557 drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
1558 {
1559 
1560 }
1561 
1562 static void
drmmode_set_cursor_position(xf86CrtcPtr crtc,int x,int y)1563 drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
1564 {
1565     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1566     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1567 
1568     drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1569 }
1570 
1571 static Bool
drmmode_set_cursor(xf86CrtcPtr crtc)1572 drmmode_set_cursor(xf86CrtcPtr crtc)
1573 {
1574     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1575     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1576     uint32_t handle = drmmode_crtc->cursor_bo->handle;
1577     modesettingPtr ms = modesettingPTR(crtc->scrn);
1578     CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen);
1579     int ret = -EINVAL;
1580 
1581     if (cursor == NullCursor)
1582 	    return TRUE;
1583 
1584     ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1585                             handle, ms->cursor_width, ms->cursor_height,
1586                             cursor->bits->xhot, cursor->bits->yhot);
1587 
1588     /* -EINVAL can mean that an old kernel supports drmModeSetCursor but
1589      * not drmModeSetCursor2, though it can mean other things too. */
1590     if (ret == -EINVAL)
1591         ret = drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1592                                handle, ms->cursor_width, ms->cursor_height);
1593 
1594     /* -ENXIO normally means that the current drm driver supports neither
1595      * cursor_set nor cursor_set2.  Disable hardware cursor support for
1596      * the rest of the session in that case. */
1597     if (ret == -ENXIO) {
1598         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1599         xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
1600 
1601         cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
1602         drmmode_crtc->drmmode->sw_cursor = TRUE;
1603     }
1604 
1605     if (ret)
1606         /* fallback to swcursor */
1607         return FALSE;
1608     return TRUE;
1609 }
1610 
1611 static void drmmode_hide_cursor(xf86CrtcPtr crtc);
1612 
1613 /*
1614  * The load_cursor_argb_check driver hook.
1615  *
1616  * Sets the hardware cursor by calling the drmModeSetCursor2 ioctl.
1617  * On failure, returns FALSE indicating that the X server should fall
1618  * back to software cursors.
1619  */
1620 static Bool
drmmode_load_cursor_argb_check(xf86CrtcPtr crtc,CARD32 * image)1621 drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image)
1622 {
1623     modesettingPtr ms = modesettingPTR(crtc->scrn);
1624     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1625     int i;
1626     uint32_t *ptr;
1627 
1628     /* cursor should be mapped already */
1629     ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr);
1630 
1631     for (i = 0; i < ms->cursor_width * ms->cursor_height; i++)
1632         ptr[i] = image[i];      // cpu_to_le32(image[i]);
1633 
1634     if (drmmode_crtc->cursor_up)
1635         return drmmode_set_cursor(crtc);
1636     return TRUE;
1637 }
1638 
1639 static void
drmmode_hide_cursor(xf86CrtcPtr crtc)1640 drmmode_hide_cursor(xf86CrtcPtr crtc)
1641 {
1642     modesettingPtr ms = modesettingPTR(crtc->scrn);
1643     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1644     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1645 
1646     drmmode_crtc->cursor_up = FALSE;
1647     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1648                      ms->cursor_width, ms->cursor_height);
1649 }
1650 
1651 static Bool
drmmode_show_cursor(xf86CrtcPtr crtc)1652 drmmode_show_cursor(xf86CrtcPtr crtc)
1653 {
1654     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1655     drmmode_crtc->cursor_up = TRUE;
1656     return drmmode_set_cursor(crtc);
1657 }
1658 
1659 static void
drmmode_crtc_gamma_set(xf86CrtcPtr crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)1660 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
1661                        uint16_t * blue, int size)
1662 {
1663     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1664     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1665 
1666     drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1667                         size, red, green, blue);
1668 }
1669 
1670 static Bool
drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)1671 drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
1672                                       PixmapPtr *target)
1673 {
1674     ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
1675     PixmapPtr screenpix = screen->GetScreenPixmap(screen);
1676     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1677     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1678     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1679     int c, total_width = 0, max_height = 0, this_x = 0;
1680 
1681     if (*target) {
1682         PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
1683         if (drmmode->fb_id) {
1684             drmModeRmFB(drmmode->fd, drmmode->fb_id);
1685             drmmode->fb_id = 0;
1686         }
1687         drmmode_crtc->prime_pixmap_x = 0;
1688         *target = NULL;
1689     }
1690 
1691     if (!ppix)
1692         return TRUE;
1693 
1694     /* iterate over all the attached crtcs to work out the bounding box */
1695     for (c = 0; c < xf86_config->num_crtc; c++) {
1696         xf86CrtcPtr iter = xf86_config->crtc[c];
1697         if (!iter->enabled && iter != crtc)
1698             continue;
1699         if (iter == crtc) {
1700             this_x = total_width;
1701             total_width += ppix->drawable.width;
1702             if (max_height < ppix->drawable.height)
1703                 max_height = ppix->drawable.height;
1704         } else {
1705             total_width += iter->mode.HDisplay;
1706             if (max_height < iter->mode.VDisplay)
1707                 max_height = iter->mode.VDisplay;
1708         }
1709     }
1710 
1711     if (total_width != screenpix->drawable.width ||
1712         max_height != screenpix->drawable.height) {
1713 
1714         if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
1715             return FALSE;
1716 
1717         screenpix = screen->GetScreenPixmap(screen);
1718         screen->width = screenpix->drawable.width = total_width;
1719         screen->height = screenpix->drawable.height = max_height;
1720     }
1721     drmmode_crtc->prime_pixmap_x = this_x;
1722     PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
1723                              RR_Rotate_0);
1724     *target = ppix;
1725     return TRUE;
1726 }
1727 
1728 static Bool
drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)1729 drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
1730                                       PixmapPtr *target)
1731 {
1732     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1733     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1734     msPixmapPrivPtr ppriv;
1735     void *ptr;
1736 
1737     if (*target) {
1738         ppriv = msGetPixmapPriv(drmmode, *target);
1739         drmModeRmFB(drmmode->fd, ppriv->fb_id);
1740         ppriv->fb_id = 0;
1741         if (ppriv->slave_damage) {
1742             DamageUnregister(ppriv->slave_damage);
1743             ppriv->slave_damage = NULL;
1744         }
1745         *target = NULL;
1746     }
1747 
1748     if (!ppix)
1749         return TRUE;
1750 
1751     ppriv = msGetPixmapPriv(drmmode, ppix);
1752     if (!ppriv->slave_damage) {
1753         ppriv->slave_damage = DamageCreate(NULL, NULL,
1754                                            DamageReportNone,
1755                                            TRUE,
1756                                            crtc->randr_crtc->pScreen,
1757                                            NULL);
1758     }
1759     ptr = drmmode_map_slave_bo(drmmode, ppriv);
1760     ppix->devPrivate.ptr = ptr;
1761     DamageRegister(&ppix->drawable, ppriv->slave_damage);
1762 
1763     if (ppriv->fb_id == 0) {
1764         drmModeAddFB(drmmode->fd, ppix->drawable.width,
1765                      ppix->drawable.height,
1766                      ppix->drawable.depth,
1767                      ppix->drawable.bitsPerPixel,
1768                      ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
1769     }
1770     *target = ppix;
1771     return TRUE;
1772 }
1773 
1774 static Bool
drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)1775 drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1776                                   PixmapPtr *target)
1777 {
1778     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1779     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1780 
1781     if (drmmode->reverse_prime_offload_mode)
1782         return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
1783     else
1784         return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
1785 }
1786 
1787 static Bool
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix)1788 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
1789 {
1790     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1791 
1792     /* Use DisableSharedPixmapFlipping before switching to single buf */
1793     if (drmmode_crtc->enable_flipping)
1794         return FALSE;
1795 
1796     return drmmode_set_target_scanout_pixmap(crtc, ppix,
1797                                              &drmmode_crtc->prime_pixmap);
1798 }
1799 
1800 static void
drmmode_clear_pixmap(PixmapPtr pixmap)1801 drmmode_clear_pixmap(PixmapPtr pixmap)
1802 {
1803     ScreenPtr screen = pixmap->drawable.pScreen;
1804     GCPtr gc;
1805 
1806     gc = GetScratchGC(pixmap->drawable.depth, screen);
1807     if (gc) {
1808         miClearDrawable(&pixmap->drawable, gc);
1809         FreeScratchGC(gc);
1810     }
1811 }
1812 
1813 static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc,int width,int height)1814 drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
1815 {
1816     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1817     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1818     int ret;
1819 
1820     if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
1821                            width, height, drmmode->kbpp)) {
1822         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1823                "Couldn't allocate shadow memory for rotated CRTC\n");
1824         return NULL;
1825     }
1826 
1827     ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
1828                             &drmmode_crtc->rotate_fb_id);
1829 
1830     if (ret) {
1831         ErrorF("failed to add rotate fb\n");
1832         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
1833         return NULL;
1834     }
1835 
1836 #ifdef GLAMOR_HAS_GBM
1837     if (drmmode->gbm)
1838         return drmmode_crtc->rotate_bo.gbm;
1839 #endif
1840     return drmmode_crtc->rotate_bo.dumb;
1841 }
1842 
1843 static PixmapPtr
drmmode_create_pixmap_header(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)1844 drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
1845                              int depth, int bitsPerPixel, int devKind,
1846                              void *pPixData)
1847 {
1848     PixmapPtr pixmap;
1849 
1850     /* width and height of 0 means don't allocate any pixmap data */
1851     pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
1852 
1853     if (pixmap) {
1854         if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
1855                                            bitsPerPixel, devKind, pPixData))
1856             return pixmap;
1857         (*pScreen->DestroyPixmap)(pixmap);
1858     }
1859     return NullPixmap;
1860 }
1861 
1862 static Bool
1863 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
1864 
1865 static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc,void * data,int width,int height)1866 drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
1867 {
1868     ScrnInfoPtr scrn = crtc->scrn;
1869     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1870     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1871     uint32_t rotate_pitch;
1872     PixmapPtr rotate_pixmap;
1873     void *pPixData = NULL;
1874 
1875     if (!data) {
1876         data = drmmode_shadow_allocate(crtc, width, height);
1877         if (!data) {
1878             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1879                        "Couldn't allocate shadow pixmap for rotated CRTC\n");
1880             return NULL;
1881         }
1882     }
1883 
1884     if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
1885         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1886                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
1887         return NULL;
1888     }
1889 
1890     pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
1891     rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo),
1892 
1893     rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
1894                                                  width, height,
1895                                                  scrn->depth,
1896                                                  drmmode->kbpp,
1897                                                  rotate_pitch,
1898                                                  pPixData);
1899 
1900     if (rotate_pixmap == NULL) {
1901         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
1902                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
1903         return NULL;
1904     }
1905 
1906     drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
1907 
1908     return rotate_pixmap;
1909 }
1910 
1911 static void
drmmode_shadow_destroy(xf86CrtcPtr crtc,PixmapPtr rotate_pixmap,void * data)1912 drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
1913 {
1914     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1915     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1916 
1917     if (rotate_pixmap) {
1918         rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
1919     }
1920 
1921     if (data) {
1922         drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
1923         drmmode_crtc->rotate_fb_id = 0;
1924 
1925         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
1926         memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
1927     }
1928 }
1929 
1930 static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)1931 drmmode_crtc_destroy(xf86CrtcPtr crtc)
1932 {
1933     drmmode_mode_ptr iterator, next;
1934     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1935     modesettingPtr ms = modesettingPTR(crtc->scrn);
1936 
1937     if (!ms->atomic_modeset)
1938         return;
1939 
1940     drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
1941     xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
1942         drm_mode_destroy(crtc, iterator);
1943     }
1944 }
1945 
1946 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
1947     .dpms = drmmode_crtc_dpms,
1948     .set_mode_major = drmmode_set_mode_major,
1949     .set_cursor_colors = drmmode_set_cursor_colors,
1950     .set_cursor_position = drmmode_set_cursor_position,
1951     .show_cursor_check = drmmode_show_cursor,
1952     .hide_cursor = drmmode_hide_cursor,
1953     .load_cursor_argb_check = drmmode_load_cursor_argb_check,
1954 
1955     .gamma_set = drmmode_crtc_gamma_set,
1956     .destroy = drmmode_crtc_destroy,
1957     .set_scanout_pixmap = drmmode_set_scanout_pixmap,
1958     .shadow_allocate = drmmode_shadow_allocate,
1959     .shadow_create = drmmode_shadow_create,
1960     .shadow_destroy = drmmode_shadow_destroy,
1961 };
1962 
1963 static uint32_t
drmmode_crtc_vblank_pipe(int crtc_id)1964 drmmode_crtc_vblank_pipe(int crtc_id)
1965 {
1966     if (crtc_id > 1)
1967         return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
1968     else if (crtc_id > 0)
1969         return DRM_VBLANK_SECONDARY;
1970     else
1971         return 0;
1972 }
1973 
1974 static Bool
is_plane_assigned(ScrnInfoPtr scrn,int plane_id)1975 is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
1976 {
1977     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
1978     int c;
1979 
1980     for (c = 0; c < xf86_config->num_crtc; c++) {
1981         xf86CrtcPtr iter = xf86_config->crtc[c];
1982         drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
1983         if (drmmode_crtc->plane_id == plane_id)
1984             return TRUE;
1985     }
1986 
1987     return FALSE;
1988 }
1989 
1990 /**
1991  * Populates the formats array, and the modifiers of each format for a drm_plane.
1992  */
1993 static Bool
populate_format_modifiers(xf86CrtcPtr crtc,const drmModePlane * kplane,uint32_t blob_id)1994 populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
1995                           uint32_t blob_id)
1996 {
1997     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1998     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1999     unsigned i, j;
2000     drmModePropertyBlobRes *blob;
2001     struct drm_format_modifier_blob *fmt_mod_blob;
2002     uint32_t *blob_formats;
2003     struct drm_format_modifier *blob_modifiers;
2004 
2005     if (!blob_id)
2006         return FALSE;
2007 
2008     blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
2009     if (!blob)
2010         return FALSE;
2011 
2012     fmt_mod_blob = blob->data;
2013     blob_formats = formats_ptr(fmt_mod_blob);
2014     blob_modifiers = modifiers_ptr(fmt_mod_blob);
2015 
2016     assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
2017 
2018     for (i = 0; i < fmt_mod_blob->count_formats; i++) {
2019         uint32_t num_modifiers = 0;
2020         uint64_t *modifiers = NULL;
2021         uint64_t *tmp;
2022         for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
2023             struct drm_format_modifier *mod = &blob_modifiers[j];
2024 
2025             if ((i < mod->offset) || (i > mod->offset + 63))
2026                 continue;
2027             if (!(mod->formats & (1 << (i - mod->offset))))
2028                 continue;
2029 
2030             num_modifiers++;
2031             tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
2032             if (!tmp) {
2033                 free(modifiers);
2034                 drmModeFreePropertyBlob(blob);
2035                 return FALSE;
2036             }
2037             modifiers = tmp;
2038             modifiers[num_modifiers - 1] = mod->modifier;
2039         }
2040 
2041         drmmode_crtc->formats[i].format = blob_formats[i];
2042         drmmode_crtc->formats[i].modifiers = modifiers;
2043         drmmode_crtc->formats[i].num_modifiers = num_modifiers;
2044     }
2045 
2046     drmModeFreePropertyBlob(blob);
2047 
2048     return TRUE;
2049 }
2050 
2051 static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc,int num)2052 drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
2053 {
2054     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2055     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2056     drmModePlaneRes *kplane_res;
2057     drmModePlane *kplane, *best_kplane = NULL;
2058     drmModeObjectProperties *props;
2059     uint32_t i, type, blob_id;
2060     int current_crtc, best_plane = 0;
2061 
2062     static drmmode_prop_enum_info_rec plane_type_enums[] = {
2063         [DRMMODE_PLANE_TYPE_PRIMARY] = {
2064             .name = "Primary",
2065         },
2066         [DRMMODE_PLANE_TYPE_OVERLAY] = {
2067             .name = "Overlay",
2068         },
2069         [DRMMODE_PLANE_TYPE_CURSOR] = {
2070             .name = "Cursor",
2071         },
2072     };
2073     static const drmmode_prop_info_rec plane_props[] = {
2074         [DRMMODE_PLANE_TYPE] = {
2075             .name = "type",
2076             .enum_values = plane_type_enums,
2077             .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
2078         },
2079         [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
2080         [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
2081         [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
2082         [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
2083         [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
2084         [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
2085         [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
2086         [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
2087         [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
2088         [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
2089         [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
2090     };
2091     drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
2092 
2093     if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
2094         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2095                    "failed to copy plane property info\n");
2096         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2097         return;
2098     }
2099 
2100     kplane_res = drmModeGetPlaneResources(drmmode->fd);
2101     if (!kplane_res) {
2102         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2103                    "failed to get plane resources: %s\n", strerror(errno));
2104         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2105         return;
2106     }
2107 
2108     for (i = 0; i < kplane_res->count_planes; i++) {
2109         int plane_id;
2110 
2111         kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
2112         if (!kplane)
2113             continue;
2114 
2115         if (!(kplane->possible_crtcs & (1 << num)) ||
2116             is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
2117             drmModeFreePlane(kplane);
2118             continue;
2119         }
2120 
2121         plane_id = kplane->plane_id;
2122 
2123         props = drmModeObjectGetProperties(drmmode->fd, plane_id,
2124                                            DRM_MODE_OBJECT_PLANE);
2125         if (!props) {
2126             xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2127                     "couldn't get plane properties\n");
2128             drmModeFreePlane(kplane);
2129             continue;
2130         }
2131 
2132         drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
2133 
2134         /* Only primary planes are important for atomic page-flipping */
2135         type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
2136                                       props, DRMMODE_PLANE_TYPE__COUNT);
2137         if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
2138             drmModeFreePlane(kplane);
2139             drmModeFreeObjectProperties(props);
2140             continue;
2141         }
2142 
2143         /* Check if plane is already on this CRTC */
2144         current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
2145                                               props, 0);
2146         if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
2147             if (best_plane) {
2148                 drmModeFreePlane(best_kplane);
2149                 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2150             }
2151             best_plane = plane_id;
2152             best_kplane = kplane;
2153             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2154                                              props, 0);
2155             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2156                                    DRMMODE_PLANE__COUNT, 1);
2157             drmModeFreeObjectProperties(props);
2158             break;
2159         }
2160 
2161         if (!best_plane) {
2162             best_plane = plane_id;
2163             best_kplane = kplane;
2164             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2165                                              props, 0);
2166             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2167                                    DRMMODE_PLANE__COUNT, 1);
2168         } else {
2169             drmModeFreePlane(kplane);
2170         }
2171 
2172         drmModeFreeObjectProperties(props);
2173     }
2174 
2175     drmmode_crtc->plane_id = best_plane;
2176     if (best_kplane) {
2177         drmmode_crtc->num_formats = best_kplane->count_formats;
2178         drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
2179                                        best_kplane->count_formats);
2180         if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
2181             for (i = 0; i < best_kplane->count_formats; i++)
2182                 drmmode_crtc->formats[i].format = best_kplane->formats[i];
2183         }
2184         drmModeFreePlane(best_kplane);
2185     }
2186 
2187     drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2188     drmModeFreePlaneResources(kplane_res);
2189 }
2190 
2191 static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num)2192 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
2193 {
2194     xf86CrtcPtr crtc;
2195     drmmode_crtc_private_ptr drmmode_crtc;
2196     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
2197     modesettingPtr ms = modesettingPTR(pScrn);
2198     drmModeObjectPropertiesPtr props;
2199     static const drmmode_prop_info_rec crtc_props[] = {
2200         [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
2201         [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
2202     };
2203 
2204     crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
2205     if (crtc == NULL)
2206         return 0;
2207     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
2208     crtc->driver_private = drmmode_crtc;
2209     drmmode_crtc->mode_crtc =
2210         drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
2211     drmmode_crtc->drmmode = drmmode;
2212     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
2213     xorg_list_init(&drmmode_crtc->mode_list);
2214 
2215     if (ms->atomic_modeset) {
2216         props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
2217                                            DRM_MODE_OBJECT_CRTC);
2218         if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
2219                                               DRMMODE_CRTC__COUNT, 0)) {
2220             xf86CrtcDestroy(crtc);
2221             return 0;
2222         }
2223 
2224         drmmode_prop_info_update(drmmode, drmmode_crtc->props,
2225                                  DRMMODE_CRTC__COUNT, props);
2226         drmModeFreeObjectProperties(props);
2227         drmmode_crtc_create_planes(crtc, num);
2228     }
2229 
2230     /* Hide any cursors which may be active from previous users */
2231     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
2232 
2233     /* Mark num'th crtc as in use on this device. */
2234     ms_ent->assigned_crtcs |= (1 << num);
2235     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
2236                    "Allocated crtc nr. %d to this screen.\n", num);
2237 
2238     return 1;
2239 }
2240 
2241 /*
2242  * Update all of the property values for an output
2243  */
2244 static void
drmmode_output_update_properties(xf86OutputPtr output)2245 drmmode_output_update_properties(xf86OutputPtr output)
2246 {
2247     drmmode_output_private_ptr drmmode_output = output->driver_private;
2248     int i, j, k;
2249     int err;
2250     drmModeConnectorPtr koutput;
2251 
2252     /* Use the most recently fetched values from the kernel */
2253     koutput = drmmode_output->mode_output;
2254 
2255     if (!koutput)
2256         return;
2257 
2258     for (i = 0; i < drmmode_output->num_props; i++) {
2259         drmmode_prop_ptr p = &drmmode_output->props[i];
2260 
2261         for (j = 0; koutput && j < koutput->count_props; j++) {
2262             if (koutput->props[j] == p->mode_prop->prop_id) {
2263 
2264                 /* Check to see if the property value has changed */
2265                 if (koutput->prop_values[j] != p->value) {
2266 
2267                     p->value = koutput->prop_values[j];
2268 
2269                     if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2270                         INT32 value = p->value;
2271 
2272                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2273                                                      XA_INTEGER, 32, PropModeReplace, 1,
2274                                                      &value, FALSE, TRUE);
2275 
2276                         if (err != 0) {
2277                             xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2278                                        "RRChangeOutputProperty error, %d\n", err);
2279                         }
2280                     }
2281                     else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2282                         for (k = 0; k < p->mode_prop->count_enums; k++)
2283                             if (p->mode_prop->enums[k].value == p->value)
2284                                 break;
2285                         if (k < p->mode_prop->count_enums) {
2286                             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2287                                                          XA_ATOM, 32, PropModeReplace, 1,
2288                                                          &p->atoms[k + 1], FALSE, TRUE);
2289                             if (err != 0) {
2290                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2291                                            "RRChangeOutputProperty error, %d\n", err);
2292                             }
2293                         }
2294                     }
2295                 }
2296                 break;
2297             }
2298         }
2299     }
2300 }
2301 
2302 static xf86OutputStatus
drmmode_output_detect(xf86OutputPtr output)2303 drmmode_output_detect(xf86OutputPtr output)
2304 {
2305     /* go to the hw and retrieve a new output struct */
2306     drmmode_output_private_ptr drmmode_output = output->driver_private;
2307     drmmode_ptr drmmode = drmmode_output->drmmode;
2308     xf86OutputStatus status;
2309 
2310     if (drmmode_output->output_id == -1)
2311         return XF86OutputStatusDisconnected;
2312 
2313     drmModeFreeConnector(drmmode_output->mode_output);
2314 
2315     drmmode_output->mode_output =
2316         drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
2317 
2318     if (!drmmode_output->mode_output) {
2319         drmmode_output->output_id = -1;
2320         return XF86OutputStatusDisconnected;
2321     }
2322 
2323     drmmode_output_update_properties(output);
2324 
2325     switch (drmmode_output->mode_output->connection) {
2326     case DRM_MODE_CONNECTED:
2327         status = XF86OutputStatusConnected;
2328         break;
2329     case DRM_MODE_DISCONNECTED:
2330         status = XF86OutputStatusDisconnected;
2331         break;
2332     default:
2333     case DRM_MODE_UNKNOWNCONNECTION:
2334         status = XF86OutputStatusUnknown;
2335         break;
2336     }
2337     return status;
2338 }
2339 
2340 static Bool
drmmode_output_mode_valid(xf86OutputPtr output,DisplayModePtr pModes)2341 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
2342 {
2343     return MODE_OK;
2344 }
2345 
2346 static int
koutput_get_prop_idx(int fd,drmModeConnectorPtr koutput,int type,const char * name)2347 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
2348         int type, const char *name)
2349 {
2350     int idx = -1;
2351 
2352     for (int i = 0; i < koutput->count_props; i++) {
2353         drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
2354 
2355         if (!prop)
2356             continue;
2357 
2358         if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
2359             idx = i;
2360 
2361         drmModeFreeProperty(prop);
2362 
2363         if (idx > -1)
2364             break;
2365     }
2366 
2367     return idx;
2368 }
2369 
2370 static int
koutput_get_prop_id(int fd,drmModeConnectorPtr koutput,int type,const char * name)2371 koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
2372         int type, const char *name)
2373 {
2374     int idx = koutput_get_prop_idx(fd, koutput, type, name);
2375 
2376     return (idx > -1) ? koutput->props[idx] : -1;
2377 }
2378 
2379 static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd,drmModeConnectorPtr koutput,const char * name)2380 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
2381 {
2382     drmModePropertyBlobPtr blob = NULL;
2383     int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
2384 
2385     if (idx > -1)
2386         blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
2387 
2388     return blob;
2389 }
2390 
2391 static void
drmmode_output_attach_tile(xf86OutputPtr output)2392 drmmode_output_attach_tile(xf86OutputPtr output)
2393 {
2394     drmmode_output_private_ptr drmmode_output = output->driver_private;
2395     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2396     drmmode_ptr drmmode = drmmode_output->drmmode;
2397     struct xf86CrtcTileInfo tile_info, *set = NULL;
2398 
2399     if (!koutput) {
2400         xf86OutputSetTile(output, NULL);
2401         return;
2402     }
2403 
2404     drmModeFreePropertyBlob(drmmode_output->tile_blob);
2405 
2406     /* look for a TILE property */
2407     drmmode_output->tile_blob =
2408         koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
2409 
2410     if (drmmode_output->tile_blob) {
2411         if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
2412             set = &tile_info;
2413     }
2414     xf86OutputSetTile(output, set);
2415 }
2416 
2417 static Bool
has_panel_fitter(xf86OutputPtr output)2418 has_panel_fitter(xf86OutputPtr output)
2419 {
2420     drmmode_output_private_ptr drmmode_output = output->driver_private;
2421     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2422     drmmode_ptr drmmode = drmmode_output->drmmode;
2423     int idx;
2424 
2425     /* Presume that if the output supports scaling, then we have a
2426      * panel fitter capable of adjust any mode to suit.
2427      */
2428     idx = koutput_get_prop_idx(drmmode->fd, koutput,
2429             DRM_MODE_PROP_ENUM, "scaling mode");
2430 
2431     return (idx > -1);
2432 }
2433 
2434 static DisplayModePtr
drmmode_output_add_gtf_modes(xf86OutputPtr output,DisplayModePtr Modes)2435 drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
2436 {
2437     xf86MonPtr mon = output->MonInfo;
2438     DisplayModePtr i, m, preferred = NULL;
2439     int max_x = 0, max_y = 0;
2440     float max_vrefresh = 0.0;
2441 
2442     if (mon && gtf_supported(mon))
2443         return Modes;
2444 
2445     if (!has_panel_fitter(output))
2446         return Modes;
2447 
2448     for (m = Modes; m; m = m->next) {
2449         if (m->type & M_T_PREFERRED)
2450             preferred = m;
2451         max_x = max(max_x, m->HDisplay);
2452         max_y = max(max_y, m->VDisplay);
2453         max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
2454     }
2455 
2456     max_vrefresh = max(max_vrefresh, 60.0);
2457     max_vrefresh *= (1 + SYNC_TOLERANCE);
2458 
2459     m = xf86GetDefaultModes();
2460     xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
2461 
2462     for (i = m; i; i = i->next) {
2463         if (xf86ModeVRefresh(i) > max_vrefresh)
2464             i->status = MODE_VSYNC;
2465         if (preferred &&
2466             i->HDisplay >= preferred->HDisplay &&
2467             i->VDisplay >= preferred->VDisplay &&
2468             xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
2469             i->status = MODE_VSYNC;
2470     }
2471 
2472     xf86PruneInvalidModes(output->scrn, &m, FALSE);
2473 
2474     return xf86ModesAdd(Modes, m);
2475 }
2476 
2477 static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)2478 drmmode_output_get_modes(xf86OutputPtr output)
2479 {
2480     drmmode_output_private_ptr drmmode_output = output->driver_private;
2481     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2482     drmmode_ptr drmmode = drmmode_output->drmmode;
2483     int i;
2484     DisplayModePtr Modes = NULL, Mode;
2485     xf86MonPtr mon = NULL;
2486 
2487     if (!koutput)
2488         return NULL;
2489 
2490     drmModeFreePropertyBlob(drmmode_output->edid_blob);
2491 
2492     /* look for an EDID property */
2493     drmmode_output->edid_blob =
2494         koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
2495 
2496     if (drmmode_output->edid_blob) {
2497         mon = xf86InterpretEDID(output->scrn->scrnIndex,
2498                                 drmmode_output->edid_blob->data);
2499         if (mon && drmmode_output->edid_blob->length > 128)
2500             mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
2501     }
2502     xf86OutputSetEDID(output, mon);
2503 
2504     drmmode_output_attach_tile(output);
2505 
2506     /* modes should already be available */
2507     for (i = 0; i < koutput->count_modes; i++) {
2508         Mode = xnfalloc(sizeof(DisplayModeRec));
2509 
2510         drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
2511         Modes = xf86ModesAdd(Modes, Mode);
2512 
2513     }
2514 
2515     return drmmode_output_add_gtf_modes(output, Modes);
2516 }
2517 
2518 static void
drmmode_output_destroy(xf86OutputPtr output)2519 drmmode_output_destroy(xf86OutputPtr output)
2520 {
2521     drmmode_output_private_ptr drmmode_output = output->driver_private;
2522     int i;
2523 
2524     drmModeFreePropertyBlob(drmmode_output->edid_blob);
2525     drmModeFreePropertyBlob(drmmode_output->tile_blob);
2526 
2527     for (i = 0; i < drmmode_output->num_props; i++) {
2528         drmModeFreeProperty(drmmode_output->props[i].mode_prop);
2529         free(drmmode_output->props[i].atoms);
2530     }
2531     free(drmmode_output->props);
2532     if (drmmode_output->mode_output) {
2533         for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
2534             drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
2535         }
2536         drmModeFreeConnector(drmmode_output->mode_output);
2537     }
2538     free(drmmode_output->mode_encoders);
2539     free(drmmode_output);
2540     output->driver_private = NULL;
2541 }
2542 
2543 static void
drmmode_output_dpms(xf86OutputPtr output,int mode)2544 drmmode_output_dpms(xf86OutputPtr output, int mode)
2545 {
2546     modesettingPtr ms = modesettingPTR(output->scrn);
2547     drmmode_output_private_ptr drmmode_output = output->driver_private;
2548     drmmode_ptr drmmode = drmmode_output->drmmode;
2549     xf86CrtcPtr crtc = output->crtc;
2550     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2551 
2552     if (!koutput)
2553         return;
2554 
2555     /* XXX Check if DPMS mode is already the right one */
2556 
2557     drmmode_output->dpms = mode;
2558 
2559     if (ms->atomic_modeset) {
2560         if (mode != DPMSModeOn && !ms->pending_modeset)
2561             drmmode_output_disable(output);
2562     } else {
2563         drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
2564                                     drmmode_output->dpms_enum_id, mode);
2565     }
2566 
2567     if (crtc) {
2568         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2569 
2570         if (mode == DPMSModeOn) {
2571             if (drmmode_crtc->need_modeset)
2572                 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2573                                        crtc->x, crtc->y);
2574 
2575             if (drmmode_crtc->enable_flipping)
2576                 drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
2577         } else {
2578             if (drmmode_crtc->enable_flipping)
2579                 drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
2580         }
2581     }
2582 
2583     return;
2584 }
2585 
2586 static Bool
drmmode_property_ignore(drmModePropertyPtr prop)2587 drmmode_property_ignore(drmModePropertyPtr prop)
2588 {
2589     if (!prop)
2590         return TRUE;
2591     /* ignore blob prop */
2592     if (prop->flags & DRM_MODE_PROP_BLOB)
2593         return TRUE;
2594     /* ignore standard property */
2595     if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
2596         !strcmp(prop->name, "CRTC_ID"))
2597         return TRUE;
2598 
2599     return FALSE;
2600 }
2601 
2602 static void
drmmode_output_create_resources(xf86OutputPtr output)2603 drmmode_output_create_resources(xf86OutputPtr output)
2604 {
2605     drmmode_output_private_ptr drmmode_output = output->driver_private;
2606     drmModeConnectorPtr mode_output = drmmode_output->mode_output;
2607     drmmode_ptr drmmode = drmmode_output->drmmode;
2608     drmModePropertyPtr drmmode_prop;
2609     int i, j, err;
2610 
2611     drmmode_output->props =
2612         calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
2613     if (!drmmode_output->props)
2614         return;
2615 
2616     drmmode_output->num_props = 0;
2617     for (i = 0, j = 0; i < mode_output->count_props; i++) {
2618         drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
2619         if (drmmode_property_ignore(drmmode_prop)) {
2620             drmModeFreeProperty(drmmode_prop);
2621             continue;
2622         }
2623         drmmode_output->props[j].mode_prop = drmmode_prop;
2624         drmmode_output->props[j].value = mode_output->prop_values[i];
2625         drmmode_output->num_props++;
2626         j++;
2627     }
2628 
2629     /* Create CONNECTOR_ID property */
2630     {
2631         Atom    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
2632         INT32   value = mode_output->connector_id;
2633 
2634         if (name != BAD_RESOURCE) {
2635             err = RRConfigureOutputProperty(output->randr_output, name,
2636                                             FALSE, FALSE, TRUE,
2637                                             1, &value);
2638             if (err != 0) {
2639                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2640                            "RRConfigureOutputProperty error, %d\n", err);
2641             }
2642             err = RRChangeOutputProperty(output->randr_output, name,
2643                                          XA_INTEGER, 32, PropModeReplace, 1,
2644                                          &value, FALSE, FALSE);
2645             if (err != 0) {
2646                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2647                            "RRChangeOutputProperty error, %d\n", err);
2648             }
2649         }
2650     }
2651 
2652     for (i = 0; i < drmmode_output->num_props; i++) {
2653         drmmode_prop_ptr p = &drmmode_output->props[i];
2654 
2655         drmmode_prop = p->mode_prop;
2656 
2657         if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
2658             INT32 prop_range[2];
2659             INT32 value = p->value;
2660 
2661             p->num_atoms = 1;
2662             p->atoms = calloc(p->num_atoms, sizeof(Atom));
2663             if (!p->atoms)
2664                 continue;
2665             p->atoms[0] =
2666                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
2667             prop_range[0] = drmmode_prop->values[0];
2668             prop_range[1] = drmmode_prop->values[1];
2669             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
2670                                             FALSE, TRUE,
2671                                             drmmode_prop->
2672                                             flags & DRM_MODE_PROP_IMMUTABLE ?
2673                                             TRUE : FALSE, 2, prop_range);
2674             if (err != 0) {
2675                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2676                            "RRConfigureOutputProperty error, %d\n", err);
2677             }
2678             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2679                                          XA_INTEGER, 32, PropModeReplace, 1,
2680                                          &value, FALSE, TRUE);
2681             if (err != 0) {
2682                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2683                            "RRChangeOutputProperty error, %d\n", err);
2684             }
2685         }
2686         else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
2687             p->num_atoms = drmmode_prop->count_enums + 1;
2688             p->atoms = calloc(p->num_atoms, sizeof(Atom));
2689             if (!p->atoms)
2690                 continue;
2691             p->atoms[0] =
2692                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
2693             for (j = 1; j <= drmmode_prop->count_enums; j++) {
2694                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
2695 
2696                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
2697             }
2698             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
2699                                             FALSE, FALSE,
2700                                             drmmode_prop->
2701                                             flags & DRM_MODE_PROP_IMMUTABLE ?
2702                                             TRUE : FALSE, p->num_atoms - 1,
2703                                             (INT32 *) &p->atoms[1]);
2704             if (err != 0) {
2705                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2706                            "RRConfigureOutputProperty error, %d\n", err);
2707             }
2708             for (j = 0; j < drmmode_prop->count_enums; j++)
2709                 if (drmmode_prop->enums[j].value == p->value)
2710                     break;
2711             /* there's always a matching value */
2712             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2713                                          XA_ATOM, 32, PropModeReplace, 1,
2714                                          &p->atoms[j + 1], FALSE, TRUE);
2715             if (err != 0) {
2716                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2717                            "RRChangeOutputProperty error, %d\n", err);
2718             }
2719         }
2720     }
2721 }
2722 
2723 static Bool
drmmode_output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)2724 drmmode_output_set_property(xf86OutputPtr output, Atom property,
2725                             RRPropertyValuePtr value)
2726 {
2727     drmmode_output_private_ptr drmmode_output = output->driver_private;
2728     drmmode_ptr drmmode = drmmode_output->drmmode;
2729     int i;
2730 
2731     for (i = 0; i < drmmode_output->num_props; i++) {
2732         drmmode_prop_ptr p = &drmmode_output->props[i];
2733 
2734         if (p->atoms[0] != property)
2735             continue;
2736 
2737         if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2738             uint32_t val;
2739 
2740             if (value->type != XA_INTEGER || value->format != 32 ||
2741                 value->size != 1)
2742                 return FALSE;
2743             val = *(uint32_t *) value->data;
2744 
2745             drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
2746                                         p->mode_prop->prop_id, (uint64_t) val);
2747             return TRUE;
2748         }
2749         else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2750             Atom atom;
2751             const char *name;
2752             int j;
2753 
2754             if (value->type != XA_ATOM || value->format != 32 ||
2755                 value->size != 1)
2756                 return FALSE;
2757             memcpy(&atom, value->data, 4);
2758             if (!(name = NameForAtom(atom)))
2759                 return FALSE;
2760 
2761             /* search for matching name string, then set its value down */
2762             for (j = 0; j < p->mode_prop->count_enums; j++) {
2763                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
2764                     drmModeConnectorSetProperty(drmmode->fd,
2765                                                 drmmode_output->output_id,
2766                                                 p->mode_prop->prop_id,
2767                                                 p->mode_prop->enums[j].value);
2768                     return TRUE;
2769                 }
2770             }
2771         }
2772     }
2773 
2774     return TRUE;
2775 }
2776 
2777 static Bool
drmmode_output_get_property(xf86OutputPtr output,Atom property)2778 drmmode_output_get_property(xf86OutputPtr output, Atom property)
2779 {
2780     return TRUE;
2781 }
2782 
2783 static const xf86OutputFuncsRec drmmode_output_funcs = {
2784     .dpms = drmmode_output_dpms,
2785     .create_resources = drmmode_output_create_resources,
2786     .set_property = drmmode_output_set_property,
2787     .get_property = drmmode_output_get_property,
2788     .detect = drmmode_output_detect,
2789     .mode_valid = drmmode_output_mode_valid,
2790 
2791     .get_modes = drmmode_output_get_modes,
2792     .destroy = drmmode_output_destroy
2793 };
2794 
2795 static int subpixel_conv_table[7] = {
2796     0,
2797     SubPixelUnknown,
2798     SubPixelHorizontalRGB,
2799     SubPixelHorizontalBGR,
2800     SubPixelVerticalRGB,
2801     SubPixelVerticalBGR,
2802     SubPixelNone
2803 };
2804 
2805 static const char *const output_names[] = {
2806     "None",
2807     "VGA",
2808     "DVI-I",
2809     "DVI-D",
2810     "DVI-A",
2811     "Composite",
2812     "SVIDEO",
2813     "LVDS",
2814     "Component",
2815     "DIN",
2816     "DP",
2817     "HDMI",
2818     "HDMI-B",
2819     "TV",
2820     "eDP",
2821     "Virtual",
2822     "DSI",
2823     "DPI",
2824 };
2825 
find_output(ScrnInfoPtr pScrn,int id)2826 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
2827 {
2828     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2829     int i;
2830     for (i = 0; i < xf86_config->num_output; i++) {
2831         xf86OutputPtr output = xf86_config->output[i];
2832         drmmode_output_private_ptr drmmode_output;
2833 
2834         drmmode_output = output->driver_private;
2835         if (drmmode_output->output_id == id)
2836             return output;
2837     }
2838     return NULL;
2839 }
2840 
parse_path_blob(drmModePropertyBlobPtr path_blob,int * conn_base_id,char ** path)2841 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
2842 {
2843     char *conn;
2844     char conn_id[5];
2845     int id, len;
2846     char *blob_data;
2847 
2848     if (!path_blob)
2849         return -1;
2850 
2851     blob_data = path_blob->data;
2852     /* we only handle MST paths for now */
2853     if (strncmp(blob_data, "mst:", 4))
2854         return -1;
2855 
2856     conn = strchr(blob_data + 4, '-');
2857     if (!conn)
2858         return -1;
2859     len = conn - (blob_data + 4);
2860     if (len + 1> 5)
2861         return -1;
2862     memcpy(conn_id, blob_data + 4, len);
2863     conn_id[len] = '\0';
2864     id = strtoul(conn_id, NULL, 10);
2865 
2866     *conn_base_id = id;
2867 
2868     *path = conn + 1;
2869     return 0;
2870 }
2871 
2872 static void
drmmode_create_name(ScrnInfoPtr pScrn,drmModeConnectorPtr koutput,char * name,drmModePropertyBlobPtr path_blob)2873 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
2874 		    drmModePropertyBlobPtr path_blob)
2875 {
2876     int ret;
2877     char *extra_path;
2878     int conn_id;
2879     xf86OutputPtr output;
2880 
2881     ret = parse_path_blob(path_blob, &conn_id, &extra_path);
2882     if (ret == -1)
2883         goto fallback;
2884 
2885     output = find_output(pScrn, conn_id);
2886     if (!output)
2887         goto fallback;
2888 
2889     snprintf(name, 32, "%s-%s", output->name, extra_path);
2890     return;
2891 
2892  fallback:
2893     if (koutput->connector_type >= ARRAY_SIZE(output_names))
2894         snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
2895     else if (pScrn->is_gpu)
2896         snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
2897     else
2898         snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
2899 }
2900 
2901 static unsigned int
drmmode_output_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num,Bool dynamic,int crtcshift)2902 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
2903 {
2904     xf86OutputPtr output;
2905     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
2906     modesettingPtr ms = modesettingPTR(pScrn);
2907     drmModeConnectorPtr koutput;
2908     drmModeEncoderPtr *kencoders = NULL;
2909     drmmode_output_private_ptr drmmode_output;
2910     char name[32];
2911     int i;
2912     Bool nonDesktop = FALSE;
2913     drmModePropertyBlobPtr path_blob = NULL;
2914     const char *s;
2915     drmModeObjectPropertiesPtr props;
2916     static const drmmode_prop_info_rec connector_props[] = {
2917         [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
2918     };
2919 
2920     koutput =
2921         drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
2922     if (!koutput)
2923         return 0;
2924 
2925     path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
2926     i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
2927     if (i >= 0)
2928         nonDesktop = koutput->prop_values[i] != 0;
2929 
2930     drmmode_create_name(pScrn, koutput, name, path_blob);
2931 
2932     if (path_blob)
2933         drmModeFreePropertyBlob(path_blob);
2934 
2935     if (path_blob && dynamic) {
2936         /* see if we have an output with this name already
2937            and hook stuff up */
2938         for (i = 0; i < xf86_config->num_output; i++) {
2939             output = xf86_config->output[i];
2940 
2941             if (strncmp(output->name, name, 32))
2942                 continue;
2943 
2944             drmmode_output = output->driver_private;
2945             drmmode_output->output_id = mode_res->connectors[num];
2946             drmmode_output->mode_output = koutput;
2947             output->non_desktop = nonDesktop;
2948             return 1;
2949         }
2950     }
2951 
2952     kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
2953     if (!kencoders) {
2954         goto out_free_encoders;
2955     }
2956 
2957     for (i = 0; i < koutput->count_encoders; i++) {
2958         kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
2959         if (!kencoders[i]) {
2960             goto out_free_encoders;
2961         }
2962     }
2963 
2964     if (xf86IsEntityShared(pScrn->entityList[0])) {
2965         if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
2966             if (!drmmode_zaphod_string_matches(pScrn, s, name))
2967                 goto out_free_encoders;
2968         } else {
2969             if (!drmmode->is_secondary && (num != 0))
2970                 goto out_free_encoders;
2971             else if (drmmode->is_secondary && (num != 1))
2972                 goto out_free_encoders;
2973         }
2974     }
2975 
2976     output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
2977     if (!output) {
2978         goto out_free_encoders;
2979     }
2980 
2981     drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
2982     if (!drmmode_output) {
2983         xf86OutputDestroy(output);
2984         goto out_free_encoders;
2985     }
2986 
2987     drmmode_output->output_id = mode_res->connectors[num];
2988     drmmode_output->mode_output = koutput;
2989     drmmode_output->mode_encoders = kencoders;
2990     drmmode_output->drmmode = drmmode;
2991     output->mm_width = koutput->mmWidth;
2992     output->mm_height = koutput->mmHeight;
2993 
2994     output->subpixel_order = subpixel_conv_table[koutput->subpixel];
2995     output->interlaceAllowed = TRUE;
2996     output->doubleScanAllowed = TRUE;
2997     output->driver_private = drmmode_output;
2998     output->non_desktop = nonDesktop;
2999 
3000     output->possible_crtcs = 0;
3001     for (i = 0; i < koutput->count_encoders; i++) {
3002         output->possible_crtcs |= (kencoders[i]->possible_crtcs >> crtcshift) & 0x7f;
3003     }
3004     /* work out the possible clones later */
3005     output->possible_clones = 0;
3006 
3007     if (ms->atomic_modeset) {
3008         if (!drmmode_prop_info_copy(drmmode_output->props_connector,
3009                                     connector_props, DRMMODE_CONNECTOR__COUNT,
3010                                     0)) {
3011             goto out_free_encoders;
3012         }
3013         props = drmModeObjectGetProperties(drmmode->fd,
3014                                            drmmode_output->output_id,
3015                                            DRM_MODE_OBJECT_CONNECTOR);
3016         drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
3017                                  DRMMODE_CONNECTOR__COUNT, props);
3018     } else {
3019         drmmode_output->dpms_enum_id =
3020             koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
3021                                 "DPMS");
3022     }
3023 
3024     if (dynamic) {
3025         output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
3026         if (output->randr_output) {
3027             drmmode_output_create_resources(output);
3028             RRPostPendingProperties(output->randr_output);
3029         }
3030     }
3031 
3032     return 1;
3033 
3034  out_free_encoders:
3035     if (kencoders) {
3036         for (i = 0; i < koutput->count_encoders; i++)
3037             drmModeFreeEncoder(kencoders[i]);
3038         free(kencoders);
3039     }
3040     drmModeFreeConnector(koutput);
3041 
3042     return 0;
3043 }
3044 
3045 static uint32_t
find_clones(ScrnInfoPtr scrn,xf86OutputPtr output)3046 find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
3047 {
3048     drmmode_output_private_ptr drmmode_output =
3049         output->driver_private, clone_drmout;
3050     int i;
3051     xf86OutputPtr clone_output;
3052     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3053     int index_mask = 0;
3054 
3055     if (drmmode_output->enc_clone_mask == 0)
3056         return index_mask;
3057 
3058     for (i = 0; i < xf86_config->num_output; i++) {
3059         clone_output = xf86_config->output[i];
3060         clone_drmout = clone_output->driver_private;
3061         if (output == clone_output)
3062             continue;
3063 
3064         if (clone_drmout->enc_mask == 0)
3065             continue;
3066         if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
3067             index_mask |= (1 << i);
3068     }
3069     return index_mask;
3070 }
3071 
3072 static void
drmmode_clones_init(ScrnInfoPtr scrn,drmmode_ptr drmmode,drmModeResPtr mode_res)3073 drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
3074 {
3075     int i, j;
3076     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3077 
3078     for (i = 0; i < xf86_config->num_output; i++) {
3079         xf86OutputPtr output = xf86_config->output[i];
3080         drmmode_output_private_ptr drmmode_output;
3081 
3082         drmmode_output = output->driver_private;
3083         drmmode_output->enc_clone_mask = 0xff;
3084         /* and all the possible encoder clones for this output together */
3085         for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
3086             int k;
3087 
3088             for (k = 0; k < mode_res->count_encoders; k++) {
3089                 if (mode_res->encoders[k] ==
3090                     drmmode_output->mode_encoders[j]->encoder_id)
3091                     drmmode_output->enc_mask |= (1 << k);
3092             }
3093 
3094             drmmode_output->enc_clone_mask &=
3095                 drmmode_output->mode_encoders[j]->possible_clones;
3096         }
3097     }
3098 
3099     for (i = 0; i < xf86_config->num_output; i++) {
3100         xf86OutputPtr output = xf86_config->output[i];
3101 
3102         output->possible_clones = find_clones(scrn, output);
3103     }
3104 }
3105 
3106 static Bool
drmmode_set_pixmap_bo(drmmode_ptr drmmode,PixmapPtr pixmap,drmmode_bo * bo)3107 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
3108 {
3109 #ifdef GLAMOR_HAS_GBM
3110     ScrnInfoPtr scrn = drmmode->scrn;
3111 
3112     if (!drmmode->glamor)
3113         return TRUE;
3114 
3115     if (!glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
3116                                                        bo->used_modifiers)) {
3117         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
3118         return FALSE;
3119     }
3120 #endif
3121 
3122     return TRUE;
3123 }
3124 
3125 Bool
drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode)3126 drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode)
3127 {
3128     ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
3129     PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
3130 
3131     if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
3132         return FALSE;
3133 
3134     return TRUE;
3135 }
3136 
3137 static Bool
drmmode_xf86crtc_resize(ScrnInfoPtr scrn,int width,int height)3138 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
3139 {
3140     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3141     modesettingPtr ms = modesettingPTR(scrn);
3142     drmmode_ptr drmmode = &ms->drmmode;
3143     drmmode_bo old_front;
3144     ScreenPtr screen = xf86ScrnToScreen(scrn);
3145     uint32_t old_fb_id;
3146     int i, pitch, old_width, old_height, old_pitch;
3147     int cpp = (scrn->bitsPerPixel + 7) / 8;
3148     int kcpp = (drmmode->kbpp + 7) / 8;
3149     PixmapPtr ppix = screen->GetScreenPixmap(screen);
3150     void *new_pixels = NULL;
3151 
3152     if (scrn->virtualX == width && scrn->virtualY == height)
3153         return TRUE;
3154 
3155     xf86DrvMsg(scrn->scrnIndex, X_INFO,
3156                "Allocate new frame buffer %dx%d stride\n", width, height);
3157 
3158     old_width = scrn->virtualX;
3159     old_height = scrn->virtualY;
3160     old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3161     old_front = drmmode->front_bo;
3162     old_fb_id = drmmode->fb_id;
3163     drmmode->fb_id = 0;
3164 
3165     if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
3166                            width, height, drmmode->kbpp))
3167         goto fail;
3168 
3169     pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3170 
3171     scrn->virtualX = width;
3172     scrn->virtualY = height;
3173     scrn->displayWidth = pitch / kcpp;
3174 
3175     if (!drmmode->gbm) {
3176         new_pixels = drmmode_map_front_bo(drmmode);
3177         if (!new_pixels)
3178             goto fail;
3179     }
3180 
3181     if (drmmode->shadow_enable) {
3182         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3183         new_pixels = calloc(1, size);
3184         if (new_pixels == NULL)
3185             goto fail;
3186         free(drmmode->shadow_fb);
3187         drmmode->shadow_fb = new_pixels;
3188     }
3189 
3190     if (drmmode->shadow_enable2) {
3191         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3192         void *fb2 = calloc(1, size);
3193         free(drmmode->shadow_fb2);
3194         drmmode->shadow_fb2 = fb2;
3195     }
3196 
3197     screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
3198                                scrn->displayWidth * cpp, new_pixels);
3199 
3200     if (!drmmode_glamor_handle_new_screen_pixmap(drmmode))
3201         goto fail;
3202 
3203     drmmode_clear_pixmap(ppix);
3204 
3205     for (i = 0; i < xf86_config->num_crtc; i++) {
3206         xf86CrtcPtr crtc = xf86_config->crtc[i];
3207 
3208         if (!crtc->enabled)
3209             continue;
3210 
3211         drmmode_set_mode_major(crtc, &crtc->mode,
3212                                crtc->rotation, crtc->x, crtc->y);
3213     }
3214 
3215     if (old_fb_id)
3216         drmModeRmFB(drmmode->fd, old_fb_id);
3217 
3218     drmmode_bo_destroy(drmmode, &old_front);
3219 
3220     return TRUE;
3221 
3222  fail:
3223     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3224     drmmode->front_bo = old_front;
3225     scrn->virtualX = old_width;
3226     scrn->virtualY = old_height;
3227     scrn->displayWidth = old_pitch / kcpp;
3228     drmmode->fb_id = old_fb_id;
3229 
3230     return FALSE;
3231 }
3232 
3233 static void
drmmode_validate_leases(ScrnInfoPtr scrn)3234 drmmode_validate_leases(ScrnInfoPtr scrn)
3235 {
3236     ScreenPtr screen = scrn->pScreen;
3237     rrScrPrivPtr scr_priv;
3238     modesettingPtr ms = modesettingPTR(scrn);
3239     drmmode_ptr drmmode = &ms->drmmode;
3240     drmModeLesseeListPtr lessees;
3241     RRLeasePtr lease, next;
3242     int l;
3243 
3244     /* Bail out if RandR wasn't initialized. */
3245     if (!dixPrivateKeyRegistered(rrPrivKey))
3246         return;
3247 
3248     scr_priv = rrGetScrPriv(screen);
3249 
3250     /* We can't talk to the kernel about leases when VT switched */
3251     if (!scrn->vtSema)
3252         return;
3253 
3254     lessees = drmModeListLessees(drmmode->fd);
3255     if (!lessees)
3256         return;
3257 
3258     xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
3259         drmmode_lease_private_ptr lease_private = lease->devPrivate;
3260 
3261         for (l = 0; l < lessees->count; l++) {
3262             if (lessees->lessees[l] == lease_private->lessee_id)
3263                 break;
3264         }
3265 
3266         /* check to see if the lease has gone away */
3267         if (l == lessees->count) {
3268             free(lease_private);
3269             lease->devPrivate = NULL;
3270             xf86CrtcLeaseTerminated(lease);
3271         }
3272     }
3273 
3274     free(lessees);
3275 }
3276 
3277 static int
drmmode_create_lease(RRLeasePtr lease,int * fd)3278 drmmode_create_lease(RRLeasePtr lease, int *fd)
3279 {
3280     ScreenPtr screen = lease->screen;
3281     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3282     modesettingPtr ms = modesettingPTR(scrn);
3283     drmmode_ptr drmmode = &ms->drmmode;
3284     int ncrtc = lease->numCrtcs;
3285     int noutput = lease->numOutputs;
3286     int nobjects;
3287     int c, o;
3288     int i;
3289     int lease_fd;
3290     uint32_t *objects;
3291     drmmode_lease_private_ptr   lease_private;
3292 
3293     nobjects = ncrtc + noutput;
3294 
3295     if (ms->atomic_modeset)
3296         nobjects += ncrtc; /* account for planes as well */
3297 
3298     if (nobjects == 0)
3299         return BadValue;
3300 
3301     lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
3302     if (!lease_private)
3303         return BadAlloc;
3304 
3305     objects = xallocarray(nobjects, sizeof (uint32_t));
3306 
3307     if (!objects) {
3308         free(lease_private);
3309         return BadAlloc;
3310     }
3311 
3312     i = 0;
3313 
3314     /* Add CRTC and plane ids */
3315     for (c = 0; c < ncrtc; c++) {
3316         xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
3317         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3318 
3319         objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
3320         if (ms->atomic_modeset)
3321             objects[i++] = drmmode_crtc->plane_id;
3322     }
3323 
3324     /* Add connector ids */
3325 
3326     for (o = 0; o < noutput; o++) {
3327         xf86OutputPtr   output = lease->outputs[o]->devPrivate;
3328         drmmode_output_private_ptr drmmode_output = output->driver_private;
3329 
3330         objects[i++] = drmmode_output->mode_output->connector_id;
3331     }
3332 
3333     /* call kernel to create lease */
3334     assert (i == nobjects);
3335 
3336     lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
3337 
3338     free(objects);
3339 
3340     if (lease_fd < 0) {
3341         free(lease_private);
3342         return BadMatch;
3343     }
3344 
3345     lease->devPrivate = lease_private;
3346 
3347     xf86CrtcLeaseStarted(lease);
3348 
3349     *fd = lease_fd;
3350     return Success;
3351 }
3352 
3353 static void
drmmode_terminate_lease(RRLeasePtr lease)3354 drmmode_terminate_lease(RRLeasePtr lease)
3355 {
3356     ScreenPtr screen = lease->screen;
3357     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3358     modesettingPtr ms = modesettingPTR(scrn);
3359     drmmode_ptr drmmode = &ms->drmmode;
3360     drmmode_lease_private_ptr lease_private = lease->devPrivate;
3361 
3362     if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
3363         free(lease_private);
3364         lease->devPrivate = NULL;
3365         xf86CrtcLeaseTerminated(lease);
3366     }
3367 }
3368 
3369 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
3370     .resize = drmmode_xf86crtc_resize,
3371     .create_lease = drmmode_create_lease,
3372     .terminate_lease = drmmode_terminate_lease
3373 };
3374 
3375 Bool
drmmode_pre_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int cpp)3376 drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
3377 {
3378     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
3379     int i;
3380     int ret;
3381     uint64_t value = 0;
3382     unsigned int crtcs_needed = 0;
3383     drmModeResPtr mode_res;
3384     int crtcshift;
3385 
3386     /* check for dumb capability */
3387     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
3388     if (ret > 0 || value != 1) {
3389         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3390                    "KMS doesn't support dumb interface\n");
3391         return FALSE;
3392     }
3393 
3394     xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
3395 
3396     drmmode->scrn = pScrn;
3397     drmmode->cpp = cpp;
3398     mode_res = drmModeGetResources(drmmode->fd);
3399     if (!mode_res)
3400         return FALSE;
3401 
3402     crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
3403     for (i = 0; i < mode_res->count_connectors; i++)
3404         crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
3405                                             crtcshift);
3406 
3407     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
3408                    "Up to %d crtcs needed for screen.\n", crtcs_needed);
3409 
3410     xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
3411                          mode_res->max_height);
3412     for (i = 0; i < mode_res->count_crtcs; i++)
3413         if (!xf86IsEntityShared(pScrn->entityList[0]) ||
3414             (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
3415             crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
3416 
3417     /* All ZaphodHeads outputs provided with matching crtcs? */
3418     if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
3419         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3420                    "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
3421                    crtcs_needed);
3422 
3423     /* workout clones */
3424     drmmode_clones_init(pScrn, drmmode, mode_res);
3425 
3426     drmModeFreeResources(mode_res);
3427     xf86ProviderSetup(pScrn, NULL, "modesetting");
3428 
3429     xf86InitialConfiguration(pScrn, TRUE);
3430 
3431     return TRUE;
3432 }
3433 
3434 Bool
drmmode_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3435 drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3436 {
3437 #ifdef GLAMOR_HAS_GBM
3438     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3439 
3440     if (drmmode->glamor) {
3441         if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
3442             return FALSE;
3443         }
3444 #ifdef GBM_BO_WITH_MODIFIERS
3445         glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
3446 #endif
3447     }
3448 #endif
3449 
3450     return TRUE;
3451 }
3452 
3453 void
drmmode_adjust_frame(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int x,int y)3454 drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3455 {
3456     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3457     xf86OutputPtr output = config->output[config->compat_output];
3458     xf86CrtcPtr crtc = output->crtc;
3459 
3460     if (crtc && crtc->enabled) {
3461         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
3462     }
3463 }
3464 
3465 Bool
drmmode_set_desired_modes(ScrnInfoPtr pScrn,drmmode_ptr drmmode,Bool set_hw,Bool ign_err)3466 drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
3467                           Bool ign_err)
3468 {
3469     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3470     Bool success = TRUE;
3471     int c;
3472 
3473     for (c = 0; c < config->num_crtc; c++) {
3474         xf86CrtcPtr crtc = config->crtc[c];
3475         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3476         xf86OutputPtr output = NULL;
3477         int o;
3478 
3479         /* Skip disabled CRTCs */
3480         if (!crtc->enabled) {
3481             if (set_hw) {
3482                 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
3483                                0, 0, 0, NULL, 0, NULL);
3484             }
3485             continue;
3486         }
3487 
3488         if (config->output[config->compat_output]->crtc == crtc)
3489             output = config->output[config->compat_output];
3490         else {
3491             for (o = 0; o < config->num_output; o++)
3492                 if (config->output[o]->crtc == crtc) {
3493                     output = config->output[o];
3494                     break;
3495                 }
3496         }
3497         /* paranoia */
3498         if (!output)
3499             continue;
3500 
3501         /* Mark that we'll need to re-set the mode for sure */
3502         memset(&crtc->mode, 0, sizeof(crtc->mode));
3503         if (!crtc->desiredMode.CrtcHDisplay) {
3504             DisplayModePtr mode =
3505                 xf86OutputFindClosestMode(output, pScrn->currentMode);
3506 
3507             if (!mode)
3508                 return FALSE;
3509             crtc->desiredMode = *mode;
3510             crtc->desiredRotation = RR_Rotate_0;
3511             crtc->desiredX = 0;
3512             crtc->desiredY = 0;
3513         }
3514 
3515         if (set_hw) {
3516             if (!crtc->funcs->
3517                 set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
3518                                crtc->desiredX, crtc->desiredY)) {
3519                 if (!ign_err)
3520                     return FALSE;
3521                 else {
3522                     success = FALSE;
3523                     crtc->enabled = FALSE;
3524                     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3525                                "Failed to set the desired mode on connector %s\n",
3526                                output->name);
3527                 }
3528             }
3529         } else {
3530             crtc->mode = crtc->desiredMode;
3531             crtc->rotation = crtc->desiredRotation;
3532             crtc->x = crtc->desiredX;
3533             crtc->y = crtc->desiredY;
3534             if (!xf86CrtcRotate(crtc))
3535                 return FALSE;
3536         }
3537     }
3538 
3539     /* Validate leases on VT re-entry */
3540     drmmode_validate_leases(pScrn);
3541 
3542     return success;
3543 }
3544 
3545 static void
drmmode_load_palette(ScrnInfoPtr pScrn,int numColors,int * indices,LOCO * colors,VisualPtr pVisual)3546 drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
3547                      int *indices, LOCO * colors, VisualPtr pVisual)
3548 {
3549     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3550     uint16_t lut_r[256], lut_g[256], lut_b[256];
3551     int index, j, i;
3552     int c;
3553 
3554     for (c = 0; c < xf86_config->num_crtc; c++) {
3555         xf86CrtcPtr crtc = xf86_config->crtc[c];
3556         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3557 
3558         for (i = 0; i < 256; i++) {
3559             lut_r[i] = drmmode_crtc->lut_r[i] << 6;
3560             lut_g[i] = drmmode_crtc->lut_g[i] << 6;
3561             lut_b[i] = drmmode_crtc->lut_b[i] << 6;
3562         }
3563 
3564         switch (pScrn->depth) {
3565         case 15:
3566             for (i = 0; i < numColors; i++) {
3567                 index = indices[i];
3568                 for (j = 0; j < 8; j++) {
3569                     lut_r[index * 8 + j] = colors[index].red << 6;
3570                     lut_g[index * 8 + j] = colors[index].green << 6;
3571                     lut_b[index * 8 + j] = colors[index].blue << 6;
3572                 }
3573             }
3574             break;
3575         case 16:
3576             for (i = 0; i < numColors; i++) {
3577                 index = indices[i];
3578 
3579                 if (i <= 31) {
3580                     for (j = 0; j < 8; j++) {
3581                         lut_r[index * 8 + j] = colors[index].red << 6;
3582                         lut_b[index * 8 + j] = colors[index].blue << 6;
3583                     }
3584                 }
3585 
3586                 for (j = 0; j < 4; j++) {
3587                     lut_g[index * 4 + j] = colors[index].green << 6;
3588                 }
3589             }
3590             break;
3591         default:
3592             for (i = 0; i < numColors; i++) {
3593                 index = indices[i];
3594                 lut_r[index] = colors[index].red << 6;
3595                 lut_g[index] = colors[index].green << 6;
3596                 lut_b[index] = colors[index].blue << 6;
3597             }
3598             break;
3599         }
3600 
3601         /* Make the change through RandR */
3602         if (crtc->randr_crtc)
3603             RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
3604         else
3605             crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
3606     }
3607 }
3608 
3609 Bool
drmmode_setup_colormap(ScreenPtr pScreen,ScrnInfoPtr pScrn)3610 drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
3611 {
3612     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
3613                    "Initializing kms color map for depth %d, %d bpc.\n",
3614                    pScrn->depth, pScrn->rgbBits);
3615     if (!miCreateDefColormap(pScreen))
3616         return FALSE;
3617 
3618     /* Adapt color map size and depth to color depth of screen. */
3619     if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
3620                              drmmode_load_palette, NULL,
3621                              CMAP_PALETTED_TRUECOLOR |
3622                              CMAP_RELOAD_ON_MODE_SWITCH))
3623         return FALSE;
3624     return TRUE;
3625 }
3626 
3627 #define DRM_MODE_LINK_STATUS_GOOD       0
3628 #define DRM_MODE_LINK_STATUS_BAD        1
3629 
3630 void
drmmode_update_kms_state(drmmode_ptr drmmode)3631 drmmode_update_kms_state(drmmode_ptr drmmode)
3632 {
3633     ScrnInfoPtr scrn = drmmode->scrn;
3634     drmModeResPtr mode_res;
3635     xf86CrtcConfigPtr  config = XF86_CRTC_CONFIG_PTR(scrn);
3636     int i, j;
3637     Bool found = FALSE;
3638     Bool changed = FALSE;
3639 
3640     /* Try to re-set the mode on all the connectors with a BAD link-state:
3641      * This may happen if a link degrades and a new modeset is necessary, using
3642      * different link-training parameters. If the kernel found that the current
3643      * mode is not achievable anymore, it should have pruned the mode before
3644      * sending the hotplug event. Try to re-set the currently-set mode to keep
3645      * the display alive, this will fail if the mode has been pruned.
3646      * In any case, we will send randr events for the Desktop Environment to
3647      * deal with it, if it wants to.
3648      */
3649     for (i = 0; i < config->num_output; i++) {
3650         xf86OutputPtr output = config->output[i];
3651         drmmode_output_private_ptr drmmode_output = output->driver_private;
3652 
3653         drmmode_output_detect(output);
3654 
3655         /* Get an updated view of the properties for the current connector and
3656          * look for the link-status property
3657          */
3658         for (j = 0; j < drmmode_output->num_props; j++) {
3659             drmmode_prop_ptr p = &drmmode_output->props[j];
3660 
3661             if (!strcmp(p->mode_prop->name, "link-status")) {
3662                 if (p->value == DRM_MODE_LINK_STATUS_BAD) {
3663                     xf86CrtcPtr crtc = output->crtc;
3664                     if (!crtc)
3665                         continue;
3666 
3667                     /* the connector got a link failure, re-set the current mode */
3668                     drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3669                                            crtc->x, crtc->y);
3670 
3671                     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
3672                                "hotplug event: connector %u's link-state is BAD, "
3673                                "tried resetting the current mode. You may be left"
3674                                "with a black screen if this fails...\n",
3675                                drmmode_output->mode_output->connector_id);
3676                 }
3677                 break;
3678             }
3679         }
3680     }
3681 
3682     mode_res = drmModeGetResources(drmmode->fd);
3683     if (!mode_res)
3684         goto out;
3685 
3686     if (mode_res->count_crtcs != config->num_crtc) {
3687         /* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
3688         goto out_free_res;
3689     }
3690 
3691     /* figure out if we have gotten rid of any connectors
3692        traverse old output list looking for outputs */
3693     for (i = 0; i < config->num_output; i++) {
3694         xf86OutputPtr output = config->output[i];
3695         drmmode_output_private_ptr drmmode_output;
3696 
3697         drmmode_output = output->driver_private;
3698         found = FALSE;
3699         for (j = 0; j < mode_res->count_connectors; j++) {
3700             if (mode_res->connectors[j] == drmmode_output->output_id) {
3701                 found = TRUE;
3702                 break;
3703             }
3704         }
3705         if (found)
3706             continue;
3707 
3708         drmModeFreeConnector(drmmode_output->mode_output);
3709         drmmode_output->mode_output = NULL;
3710         drmmode_output->output_id = -1;
3711 
3712         changed = TRUE;
3713     }
3714 
3715     /* find new output ids we don't have outputs for */
3716     for (i = 0; i < mode_res->count_connectors; i++) {
3717         found = FALSE;
3718 
3719         for (j = 0; j < config->num_output; j++) {
3720             xf86OutputPtr output = config->output[j];
3721             drmmode_output_private_ptr drmmode_output;
3722 
3723             drmmode_output = output->driver_private;
3724             if (mode_res->connectors[i] == drmmode_output->output_id) {
3725                 found = TRUE;
3726                 break;
3727             }
3728         }
3729         if (found)
3730             continue;
3731 
3732         changed = TRUE;
3733         drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
3734     }
3735 
3736     if (changed) {
3737         RRSetChanged(xf86ScrnToScreen(scrn));
3738         RRTellChanged(xf86ScrnToScreen(scrn));
3739     }
3740 
3741 out_free_res:
3742 
3743     /* Check to see if a lessee has disappeared */
3744     drmmode_validate_leases(scrn);
3745 
3746     drmModeFreeResources(mode_res);
3747 out:
3748     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
3749 }
3750 
3751 #undef DRM_MODE_LINK_STATUS_BAD
3752 #undef DRM_MODE_LINK_STATUS_GOOD
3753 
3754 #ifdef CONFIG_UDEV_KMS
3755 
3756 static void
drmmode_handle_uevents(int fd,void * closure)3757 drmmode_handle_uevents(int fd, void *closure)
3758 {
3759     drmmode_ptr drmmode = closure;
3760     struct udev_device *dev;
3761     Bool found = FALSE;
3762 
3763     while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
3764         udev_device_unref(dev);
3765         found = TRUE;
3766     }
3767     if (!found)
3768         return;
3769 
3770     drmmode_update_kms_state(drmmode);
3771 }
3772 
3773 #endif
3774 
3775 void
drmmode_uevent_init(ScrnInfoPtr scrn,drmmode_ptr drmmode)3776 drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3777 {
3778 #ifdef CONFIG_UDEV_KMS
3779     struct udev *u;
3780     struct udev_monitor *mon;
3781 
3782     u = udev_new();
3783     if (!u)
3784         return;
3785     mon = udev_monitor_new_from_netlink(u, "udev");
3786     if (!mon) {
3787         udev_unref(u);
3788         return;
3789     }
3790 
3791     if (udev_monitor_filter_add_match_subsystem_devtype(mon,
3792                                                         "drm",
3793                                                         "drm_minor") < 0 ||
3794         udev_monitor_enable_receiving(mon) < 0) {
3795         udev_monitor_unref(mon);
3796         udev_unref(u);
3797         return;
3798     }
3799 
3800     drmmode->uevent_handler =
3801         xf86AddGeneralHandler(udev_monitor_get_fd(mon),
3802                               drmmode_handle_uevents, drmmode);
3803 
3804     drmmode->uevent_monitor = mon;
3805 #endif
3806 }
3807 
3808 void
drmmode_uevent_fini(ScrnInfoPtr scrn,drmmode_ptr drmmode)3809 drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
3810 {
3811 #ifdef CONFIG_UDEV_KMS
3812     if (drmmode->uevent_handler) {
3813         struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
3814 
3815         xf86RemoveGeneralHandler(drmmode->uevent_handler);
3816 
3817         udev_monitor_unref(drmmode->uevent_monitor);
3818         udev_unref(u);
3819     }
3820 #endif
3821 }
3822 
3823 /* create front and cursor BOs */
3824 Bool
drmmode_create_initial_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3825 drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3826 {
3827     modesettingPtr ms = modesettingPTR(pScrn);
3828     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3829     int width;
3830     int height;
3831     int bpp = ms->drmmode.kbpp;
3832     int i;
3833     int cpp = (bpp + 7) / 8;
3834 
3835     width = pScrn->virtualX;
3836     height = pScrn->virtualY;
3837 
3838     if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
3839         return FALSE;
3840     pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
3841 
3842     width = ms->cursor_width;
3843     height = ms->cursor_height;
3844     bpp = 32;
3845     for (i = 0; i < xf86_config->num_crtc; i++) {
3846         xf86CrtcPtr crtc = xf86_config->crtc[i];
3847         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3848 
3849         drmmode_crtc->cursor_bo =
3850             dumb_bo_create(drmmode->fd, width, height, bpp);
3851     }
3852     return TRUE;
3853 }
3854 
3855 void *
drmmode_map_front_bo(drmmode_ptr drmmode)3856 drmmode_map_front_bo(drmmode_ptr drmmode)
3857 {
3858     return drmmode_bo_map(drmmode, &drmmode->front_bo);
3859 }
3860 
3861 void *
drmmode_map_slave_bo(drmmode_ptr drmmode,msPixmapPrivPtr ppriv)3862 drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
3863 {
3864     int ret;
3865 
3866     if (ppriv->backing_bo->ptr)
3867         return ppriv->backing_bo->ptr;
3868 
3869     ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
3870     if (ret)
3871         return NULL;
3872 
3873     return ppriv->backing_bo->ptr;
3874 }
3875 
3876 Bool
drmmode_map_cursor_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3877 drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3878 {
3879     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3880     int i, ret;
3881 
3882     for (i = 0; i < xf86_config->num_crtc; i++) {
3883         xf86CrtcPtr crtc = xf86_config->crtc[i];
3884         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3885 
3886         ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
3887         if (ret)
3888             return FALSE;
3889     }
3890     return TRUE;
3891 }
3892 
3893 void
drmmode_free_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3894 drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3895 {
3896     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3897     int i;
3898 
3899     if (drmmode->fb_id) {
3900         drmModeRmFB(drmmode->fd, drmmode->fb_id);
3901         drmmode->fb_id = 0;
3902     }
3903 
3904     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3905 
3906     for (i = 0; i < xf86_config->num_crtc; i++) {
3907         xf86CrtcPtr crtc = xf86_config->crtc[i];
3908         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3909 
3910         dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
3911     }
3912 }
3913 
3914 /* ugly workaround to see if we can create 32bpp */
3915 void
drmmode_get_default_bpp(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int * depth,int * bpp)3916 drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
3917                         int *bpp)
3918 {
3919     drmModeResPtr mode_res;
3920     uint64_t value;
3921     struct dumb_bo *bo;
3922     uint32_t fb_id;
3923     int ret;
3924 
3925     /* 16 is fine */
3926     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
3927     if (!ret && (value == 16 || value == 8)) {
3928         *depth = value;
3929         *bpp = value;
3930         return;
3931     }
3932 
3933     *depth = 24;
3934     mode_res = drmModeGetResources(drmmode->fd);
3935     if (!mode_res)
3936         return;
3937 
3938     if (mode_res->min_width == 0)
3939         mode_res->min_width = 1;
3940     if (mode_res->min_height == 0)
3941         mode_res->min_height = 1;
3942     /*create a bo */
3943     bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
3944                         32);
3945     if (!bo) {
3946         *bpp = 24;
3947         goto out;
3948     }
3949 
3950     ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
3951                        24, 32, bo->pitch, bo->handle, &fb_id);
3952 
3953     if (ret) {
3954         *bpp = 24;
3955         dumb_bo_destroy(drmmode->fd, bo);
3956         goto out;
3957     }
3958 
3959     drmModeRmFB(drmmode->fd, fb_id);
3960     *bpp = 32;
3961 
3962     dumb_bo_destroy(drmmode->fd, bo);
3963  out:
3964     drmModeFreeResources(mode_res);
3965     return;
3966 }
3967 
3968 /*
3969  * We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
3970  * is active. When a swcursor is active we disabe page-flipping.
3971  */
3972 
drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,ScrnInfoPtr scrn,int x,int y)3973 static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
3974                                          ScrnInfoPtr scrn, int x, int y)
3975 {
3976     modesettingPtr ms = modesettingPTR(scrn);
3977     CursorPtr cursor = sprite_priv->cursor;
3978     Bool sprite_visible = sprite_priv->sprite_visible;
3979 
3980     if (cursor) {
3981         x -= cursor->bits->xhot;
3982         y -= cursor->bits->yhot;
3983 
3984         sprite_priv->sprite_visible =
3985             x < scrn->virtualX && y < scrn->virtualY &&
3986             (x + cursor->bits->width > 0) &&
3987             (y + cursor->bits->height > 0);
3988     } else {
3989         sprite_priv->sprite_visible = FALSE;
3990     }
3991 
3992     ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
3993 }
3994 
drmmode_sprite_set_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)3995 static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
3996                                       CursorPtr pCursor, int x, int y)
3997 {
3998     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
3999     modesettingPtr ms = modesettingPTR(scrn);
4000     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4001 
4002     sprite_priv->cursor = pCursor;
4003     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4004 
4005     ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
4006 }
4007 
drmmode_sprite_move_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)4008 static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4009                                        int x, int y)
4010 {
4011     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4012     modesettingPtr ms = modesettingPTR(scrn);
4013     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4014 
4015     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4016 
4017     ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
4018 }
4019 
drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4020 static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
4021                                                   ScreenPtr pScreen,
4022                                                   CursorPtr pCursor)
4023 {
4024     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4025     modesettingPtr ms = modesettingPTR(scrn);
4026 
4027     return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
4028 }
4029 
drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4030 static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
4031                                                     ScreenPtr pScreen,
4032                                                     CursorPtr pCursor)
4033 {
4034     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4035     modesettingPtr ms = modesettingPTR(scrn);
4036 
4037     return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
4038 }
4039 
drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,ScreenPtr pScreen)4040 static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
4041                                                     ScreenPtr pScreen)
4042 {
4043     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4044     modesettingPtr ms = modesettingPTR(scrn);
4045 
4046     return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
4047 }
4048 
drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,ScreenPtr pScreen)4049 static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
4050                                                  ScreenPtr pScreen)
4051 {
4052     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4053     modesettingPtr ms = modesettingPTR(scrn);
4054 
4055     ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
4056 }
4057 
4058 miPointerSpriteFuncRec drmmode_sprite_funcs = {
4059     .RealizeCursor = drmmode_sprite_realize_realize_cursor,
4060     .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
4061     .SetCursor = drmmode_sprite_set_cursor,
4062     .MoveCursor = drmmode_sprite_move_cursor,
4063     .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
4064     .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
4065 };
4066