xref: /OK3568_Linux_fs/external/xserver/hw/xfree86/drivers/modesetting/drmmode_display.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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 <sys/time.h>
36 #include <unistd.h>
37 #include "dumb_bo.h"
38 #include "inputstr.h"
39 #include "xf86str.h"
40 #include "X11/Xatom.h"
41 #include "mi.h"
42 #include "micmap.h"
43 #include "xf86cmap.h"
44 #include "xf86DDC.h"
45 #include <drm_fourcc.h>
46 #include <drm_mode.h>
47 
48 #include <xf86drm.h>
49 #include "xf86Crtc.h"
50 #include "drmmode_display.h"
51 #include "present.h"
52 
53 #include <cursorstr.h>
54 
55 #include <X11/extensions/dpmsconst.h>
56 
57 #include "driver.h"
58 
59 static Bool drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height);
60 
61 static void drmmode_destroy_flip_fb(xf86CrtcPtr crtc);
62 static Bool drmmode_create_flip_fb(xf86CrtcPtr crtc);
63 static Bool drmmode_apply_transform(xf86CrtcPtr crtc);
64 
65 static inline uint32_t *
formats_ptr(struct drm_format_modifier_blob * blob)66 formats_ptr(struct drm_format_modifier_blob *blob)
67 {
68     return (uint32_t *)(((char *)blob) + blob->formats_offset);
69 }
70 
71 static inline struct drm_format_modifier *
modifiers_ptr(struct drm_format_modifier_blob * blob)72 modifiers_ptr(struct drm_format_modifier_blob *blob)
73 {
74     return (struct drm_format_modifier *)(((char *)blob) + blob->modifiers_offset);
75 }
76 
77 static uint32_t
get_opaque_format(uint32_t format)78 get_opaque_format(uint32_t format)
79 {
80     switch (format) {
81     case DRM_FORMAT_ARGB8888:
82         return DRM_FORMAT_XRGB8888;
83     case DRM_FORMAT_ARGB2101010:
84         return DRM_FORMAT_XRGB2101010;
85     default:
86         return format;
87     }
88 }
89 
90 Bool
drmmode_is_format_supported(ScrnInfoPtr scrn,uint32_t format,uint64_t modifier)91 drmmode_is_format_supported(ScrnInfoPtr scrn, uint32_t format, uint64_t modifier)
92 {
93     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
94     int c, i, j;
95 
96     /* BO are imported as opaque surface, so let's pretend there is no alpha */
97     format = get_opaque_format(format);
98 
99     for (c = 0; c < xf86_config->num_crtc; c++) {
100         xf86CrtcPtr crtc = xf86_config->crtc[c];
101         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
102         Bool found = FALSE;
103 
104         if (!crtc->enabled)
105             continue;
106 
107         if (drmmode_crtc->num_formats == 0)
108             continue;
109 
110         for (i = 0; i < drmmode_crtc->num_formats; i++) {
111             drmmode_format_ptr iter = &drmmode_crtc->formats[i];
112 
113             if (iter->format != format)
114                 continue;
115 
116             if (modifier == DRM_FORMAT_MOD_INVALID ||
117                 iter->num_modifiers == 0) {
118                 found = TRUE;
119                 break;
120             }
121 
122             for (j = 0; j < iter->num_modifiers; j++) {
123                 if (iter->modifiers[j] == modifier) {
124                     found = TRUE;
125                     break;
126                 }
127             }
128 
129             break;
130         }
131 
132         if (!found)
133             return FALSE;
134     }
135 
136     return TRUE;
137 }
138 
139 #ifdef GBM_BO_WITH_MODIFIERS
140 static uint32_t
get_modifiers_set(ScrnInfoPtr scrn,uint32_t format,uint64_t ** modifiers,Bool enabled_crtc_only,Bool exclude_multiplane)141 get_modifiers_set(ScrnInfoPtr scrn, uint32_t format, uint64_t **modifiers,
142                   Bool enabled_crtc_only, Bool exclude_multiplane)
143 {
144     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
145     modesettingPtr ms = modesettingPTR(scrn);
146     drmmode_ptr drmmode = &ms->drmmode;
147     int c, i, j, k, count_modifiers = 0;
148     uint64_t *tmp, *ret = NULL;
149 
150     /* BOs are imported as opaque surfaces, so pretend the same thing here */
151     format = get_opaque_format(format);
152 
153     *modifiers = NULL;
154     for (c = 0; c < xf86_config->num_crtc; c++) {
155         xf86CrtcPtr crtc = xf86_config->crtc[c];
156         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
157 
158         if (enabled_crtc_only && !crtc->enabled)
159             continue;
160 
161         for (i = 0; i < drmmode_crtc->num_formats; i++) {
162             drmmode_format_ptr iter = &drmmode_crtc->formats[i];
163 
164             if (iter->format != format)
165                 continue;
166 
167             for (j = 0; j < iter->num_modifiers; j++) {
168                 Bool found = FALSE;
169 
170 		/* Don't choose multi-plane formats for our screen pixmap.
171 		 * These will get used with frontbuffer rendering, which will
172 		 * lead to worse-than-tearing with multi-plane formats, as the
173 		 * primary and auxiliary planes go out of sync. */
174 		if (exclude_multiplane &&
175                     gbm_device_get_format_modifier_plane_count(drmmode->gbm,
176                                                                format,
177                                                                iter->modifiers[j]) > 1) {
178                     continue;
179                 }
180 
181                 for (k = 0; k < count_modifiers; k++) {
182                     if (iter->modifiers[j] == ret[k])
183                         found = TRUE;
184                 }
185                 if (!found) {
186                     count_modifiers++;
187                     tmp = realloc(ret, count_modifiers * sizeof(uint64_t));
188                     if (!tmp) {
189                         free(ret);
190                         return 0;
191                     }
192                     ret = tmp;
193                     ret[count_modifiers - 1] = iter->modifiers[j];
194                 }
195             }
196         }
197     }
198 
199     *modifiers = ret;
200     return count_modifiers;
201 }
202 
203 static Bool
get_drawable_modifiers(DrawablePtr draw,uint32_t format,uint32_t * num_modifiers,uint64_t ** modifiers)204 get_drawable_modifiers(DrawablePtr draw, uint32_t format,
205                        uint32_t *num_modifiers, uint64_t **modifiers)
206 {
207     ScrnInfoPtr scrn = xf86ScreenToScrn(draw->pScreen);
208     modesettingPtr ms = modesettingPTR(scrn);
209 
210     if (!present_can_window_flip((WindowPtr) draw) ||
211         !ms->drmmode.pageflip || ms->drmmode.dri2_flipping || !scrn->vtSema) {
212         *num_modifiers = 0;
213         *modifiers = NULL;
214         return TRUE;
215     }
216 
217     *num_modifiers = get_modifiers_set(scrn, format, modifiers, TRUE, FALSE);
218     return TRUE;
219 }
220 #endif
221 
222 static Bool
drmmode_zaphod_string_matches(ScrnInfoPtr scrn,const char * s,char * output_name)223 drmmode_zaphod_string_matches(ScrnInfoPtr scrn, const char *s, char *output_name)
224 {
225     char **token = xstrtokenize(s, ", \t\n\r");
226     Bool ret = FALSE;
227 
228     if (!token)
229         return FALSE;
230 
231     for (int i = 0; token[i]; i++) {
232         if (strcmp(token[i], output_name) == 0)
233             ret = TRUE;
234 
235         free(token[i]);
236     }
237 
238     free(token);
239 
240     return ret;
241 }
242 
243 static uint64_t
drmmode_prop_get_value(drmmode_prop_info_ptr info,drmModeObjectPropertiesPtr props,uint64_t def)244 drmmode_prop_get_value(drmmode_prop_info_ptr info,
245                        drmModeObjectPropertiesPtr props,
246                        uint64_t def)
247 {
248     unsigned int i;
249 
250     if (info->prop_id == 0)
251         return def;
252 
253     for (i = 0; i < props->count_props; i++) {
254         unsigned int j;
255 
256         if (props->props[i] != info->prop_id)
257             continue;
258 
259         /* Simple (non-enum) types can return the value directly */
260         if (info->num_enum_values == 0)
261             return props->prop_values[i];
262 
263         /* Map from raw value to enum value */
264         for (j = 0; j < info->num_enum_values; j++) {
265             if (!info->enum_values[j].valid)
266                 continue;
267             if (info->enum_values[j].value != props->prop_values[i])
268                 continue;
269 
270             return j;
271         }
272     }
273 
274     return def;
275 }
276 
277 static uint32_t
drmmode_prop_info_update(drmmode_ptr drmmode,drmmode_prop_info_ptr info,unsigned int num_infos,drmModeObjectProperties * props)278 drmmode_prop_info_update(drmmode_ptr drmmode,
279                          drmmode_prop_info_ptr info,
280                          unsigned int num_infos,
281                          drmModeObjectProperties *props)
282 {
283     drmModePropertyRes *prop;
284     uint32_t valid_mask = 0;
285     unsigned i, j;
286 
287     assert(num_infos <= 32 && "update return type");
288 
289     for (i = 0; i < props->count_props; i++) {
290         Bool props_incomplete = FALSE;
291         unsigned int k;
292 
293         for (j = 0; j < num_infos; j++) {
294             if (info[j].prop_id == props->props[i])
295                 break;
296             if (!info[j].prop_id)
297                 props_incomplete = TRUE;
298         }
299 
300         /* We've already discovered this property. */
301         if (j != num_infos)
302             continue;
303 
304         /* We haven't found this property ID, but as we've already
305          * found all known properties, we don't need to look any
306          * further. */
307         if (!props_incomplete)
308             break;
309 
310         prop = drmModeGetProperty(drmmode->fd, props->props[i]);
311         if (!prop)
312             continue;
313 
314         for (j = 0; j < num_infos; j++) {
315             if (!strcmp(prop->name, info[j].name))
316                 break;
317         }
318 
319         /* We don't know/care about this property. */
320         if (j == num_infos) {
321             drmModeFreeProperty(prop);
322             continue;
323         }
324 
325         info[j].prop_id = props->props[i];
326         info[j].value = props->prop_values[i];
327         valid_mask |= 1U << j;
328 
329         if (info[j].num_enum_values == 0) {
330             drmModeFreeProperty(prop);
331             continue;
332         }
333 
334         if (!(prop->flags & DRM_MODE_PROP_ENUM)) {
335             xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
336                        "expected property %s to be an enum,"
337                        " but it is not; ignoring\n", prop->name);
338             drmModeFreeProperty(prop);
339             continue;
340         }
341 
342         for (k = 0; k < info[j].num_enum_values; k++) {
343             int l;
344 
345             if (info[j].enum_values[k].valid)
346                 continue;
347 
348             for (l = 0; l < prop->count_enums; l++) {
349                 if (!strcmp(prop->enums[l].name,
350                             info[j].enum_values[k].name))
351                     break;
352             }
353 
354             if (l == prop->count_enums)
355                 continue;
356 
357             info[j].enum_values[k].valid = TRUE;
358             info[j].enum_values[k].value = prop->enums[l].value;
359         }
360 
361         drmModeFreeProperty(prop);
362     }
363 
364     return valid_mask;
365 }
366 
367 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)368 drmmode_prop_info_copy(drmmode_prop_info_ptr dst,
369 		       const drmmode_prop_info_rec *src,
370 		       unsigned int num_props,
371 		       Bool copy_prop_id)
372 {
373     unsigned int i;
374 
375     memcpy(dst, src, num_props * sizeof(*dst));
376 
377     for (i = 0; i < num_props; i++) {
378         unsigned int j;
379 
380         if (copy_prop_id)
381             dst[i].prop_id = src[i].prop_id;
382         else
383             dst[i].prop_id = 0;
384 
385         if (src[i].num_enum_values == 0)
386             continue;
387 
388         dst[i].enum_values =
389             malloc(src[i].num_enum_values *
390                     sizeof(*dst[i].enum_values));
391         if (!dst[i].enum_values)
392             goto err;
393 
394         memcpy(dst[i].enum_values, src[i].enum_values,
395                 src[i].num_enum_values * sizeof(*dst[i].enum_values));
396 
397         for (j = 0; j < dst[i].num_enum_values; j++)
398             dst[i].enum_values[j].valid = FALSE;
399     }
400 
401     return TRUE;
402 
403 err:
404     while (i--)
405         free(dst[i].enum_values);
406     return FALSE;
407 }
408 
409 static void
drmmode_prop_info_free(drmmode_prop_info_ptr info,int num_props)410 drmmode_prop_info_free(drmmode_prop_info_ptr info, int num_props)
411 {
412     int i;
413 
414     for (i = 0; i < num_props; i++)
415         free(info[i].enum_values);
416 }
417 
418 static void
419 drmmode_ConvertToKMode(xf86CrtcPtr crtc,
420                        drmModeModeInfo * kmode, DisplayModePtr mode);
421 
422 
423 static int
plane_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_plane_property prop,uint64_t val)424 plane_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
425                enum drmmode_plane_property prop, uint64_t val)
426 {
427     drmmode_prop_info_ptr info = &drmmode_crtc->props_plane[prop];
428     int ret;
429 
430     if (!info)
431         return -1;
432 
433     ret = drmModeAtomicAddProperty(req, drmmode_crtc->plane_id,
434                                    info->prop_id, val);
435     return (ret <= 0) ? -1 : 0;
436 }
437 
438 static int
plane_add_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,uint32_t fb_id,int x,int y)439 plane_add_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
440                 uint32_t fb_id, int x, int y)
441 {
442     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
443     int ret = 0;
444 
445     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_FB_ID,
446                           fb_id);
447     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_ID,
448                           fb_id ? drmmode_crtc->mode_crtc->crtc_id : 0);
449     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_X, x << 16);
450     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_Y, y << 16);
451     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_W,
452                           crtc->mode.HDisplay << 16);
453     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_SRC_H,
454                           crtc->mode.VDisplay << 16);
455     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_X, 0);
456     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_Y, 0);
457     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_W,
458                           crtc->mode.HDisplay);
459     ret |= plane_add_prop(req, drmmode_crtc, DRMMODE_PLANE_CRTC_H,
460                           crtc->mode.VDisplay);
461 
462     return ret;
463 }
464 
465 static int
crtc_add_prop(drmModeAtomicReq * req,drmmode_crtc_private_ptr drmmode_crtc,enum drmmode_crtc_property prop,uint64_t val)466 crtc_add_prop(drmModeAtomicReq *req, drmmode_crtc_private_ptr drmmode_crtc,
467               enum drmmode_crtc_property prop, uint64_t val)
468 {
469     drmmode_prop_info_ptr info = &drmmode_crtc->props[prop];
470     int ret;
471 
472     if (!info)
473         return -1;
474 
475     ret = drmModeAtomicAddProperty(req, drmmode_crtc->mode_crtc->crtc_id,
476                                    info->prop_id, val);
477     return (ret <= 0) ? -1 : 0;
478 }
479 
480 static int
connector_add_prop(drmModeAtomicReq * req,drmmode_output_private_ptr drmmode_output,enum drmmode_connector_property prop,uint64_t val)481 connector_add_prop(drmModeAtomicReq *req, drmmode_output_private_ptr drmmode_output,
482                    enum drmmode_connector_property prop, uint64_t val)
483 {
484     drmmode_prop_info_ptr info = &drmmode_output->props_connector[prop];
485     int ret;
486 
487     if (!info)
488         return -1;
489 
490     ret = drmModeAtomicAddProperty(req, drmmode_output->output_id,
491                                    info->prop_id, val);
492     return (ret <= 0) ? -1 : 0;
493 }
494 
495 static int
drmmode_CompareKModes(drmModeModeInfo * kmode,drmModeModeInfo * other)496 drmmode_CompareKModes(drmModeModeInfo * kmode, drmModeModeInfo * other)
497 {
498     return memcmp(kmode, other, sizeof(*kmode));
499 }
500 
501 static int
drm_mode_ensure_blob(xf86CrtcPtr crtc,drmModeModeInfo mode_info)502 drm_mode_ensure_blob(xf86CrtcPtr crtc, drmModeModeInfo mode_info)
503 {
504     modesettingPtr ms = modesettingPTR(crtc->scrn);
505     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
506     drmmode_mode_ptr mode;
507     int ret;
508 
509     if (drmmode_crtc->current_mode &&
510         drmmode_CompareKModes(&drmmode_crtc->current_mode->mode_info, &mode_info) == 0)
511         return 0;
512 
513     mode = calloc(sizeof(drmmode_mode_rec), 1);
514     if (!mode)
515         return -1;
516 
517     mode->mode_info = mode_info;
518     ret = drmModeCreatePropertyBlob(ms->fd,
519                                     &mode->mode_info,
520                                     sizeof(mode->mode_info),
521                                     &mode->blob_id);
522     drmmode_crtc->current_mode = mode;
523     xorg_list_add(&mode->entry, &drmmode_crtc->mode_list);
524 
525     return ret;
526 }
527 
528 static int
crtc_add_dpms_props(drmModeAtomicReq * req,xf86CrtcPtr crtc,int new_dpms,Bool * active)529 crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
530                     int new_dpms, Bool *active)
531 {
532     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
533     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
534     Bool crtc_active = FALSE;
535     int i;
536     int ret = 0;
537 
538     for (i = 0; i < xf86_config->num_output; i++) {
539         xf86OutputPtr output = xf86_config->output[i];
540         drmmode_output_private_ptr drmmode_output = output->driver_private;
541 
542         if (output->crtc != crtc) {
543             if (drmmode_output->current_crtc == crtc) {
544                 ret |= connector_add_prop(req, drmmode_output,
545                                           DRMMODE_CONNECTOR_CRTC_ID, 0);
546             }
547             continue;
548         }
549 
550         if (drmmode_output->output_id == -1)
551             continue;
552 
553         if (new_dpms == DPMSModeOn)
554             crtc_active = TRUE;
555 
556         ret |= connector_add_prop(req, drmmode_output,
557                                   DRMMODE_CONNECTOR_CRTC_ID,
558                                   crtc_active ?
559                                       drmmode_crtc->mode_crtc->crtc_id : 0);
560     }
561 
562     if (crtc_active) {
563         drmModeModeInfo kmode;
564 
565         drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
566         ret |= drm_mode_ensure_blob(crtc, kmode);
567 
568         ret |= crtc_add_prop(req, drmmode_crtc,
569                              DRMMODE_CRTC_ACTIVE, 1);
570         ret |= crtc_add_prop(req, drmmode_crtc,
571                              DRMMODE_CRTC_MODE_ID,
572                              drmmode_crtc->current_mode->blob_id);
573     } else {
574         ret |= crtc_add_prop(req, drmmode_crtc,
575                              DRMMODE_CRTC_ACTIVE, 0);
576         ret |= crtc_add_prop(req, drmmode_crtc,
577                              DRMMODE_CRTC_MODE_ID, 0);
578     }
579 
580     if (active)
581         *active = crtc_active;
582 
583     return ret;
584 }
585 
586 static void
drm_mode_destroy(xf86CrtcPtr crtc,drmmode_mode_ptr mode)587 drm_mode_destroy(xf86CrtcPtr crtc, drmmode_mode_ptr mode)
588 {
589     modesettingPtr ms = modesettingPTR(crtc->scrn);
590     if (mode->blob_id)
591         drmModeDestroyPropertyBlob(ms->fd, mode->blob_id);
592     xorg_list_del(&mode->entry);
593     free(mode);
594 }
595 
596 static int
drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)597 drmmode_crtc_can_test_mode(xf86CrtcPtr crtc)
598 {
599     modesettingPtr ms = modesettingPTR(crtc->scrn);
600 
601     return ms->atomic_modeset;
602 }
603 
604 static Bool
drmmode_crtc_get_fb_id(xf86CrtcPtr crtc,uint32_t * fb_id,int * x,int * y)605 drmmode_crtc_get_fb_id(xf86CrtcPtr crtc, uint32_t *fb_id, int *x, int *y)
606 {
607     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
608     drmmode_ptr drmmode = drmmode_crtc->drmmode;
609     int ret;
610 
611     *fb_id = 0;
612 
613     if (drmmode_crtc->prime_pixmap) {
614         if (!drmmode->reverse_prime_offload_mode) {
615             msPixmapPrivPtr ppriv =
616                 msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap);
617             *fb_id = ppriv->fb_id;
618             *x = 0;
619         } else
620             *x = drmmode_crtc->prime_pixmap_x;
621         *y = 0;
622     }
623     else if (drmmode_crtc->rotate_fb_id) {
624         *fb_id = drmmode_crtc->rotate_fb_id;
625         *x = *y = 0;
626     } else {
627         *fb_id = drmmode->fb_id;
628         *x = crtc->x;
629         *y = crtc->y;
630     }
631 
632     if (*fb_id == 0) {
633         ret = drmmode_bo_import(drmmode, &drmmode->front_bo,
634                                 &drmmode->fb_id);
635         if (ret < 0) {
636             ErrorF("failed to add fb %d\n", ret);
637             return FALSE;
638         }
639         *fb_id = drmmode->fb_id;
640     }
641 
642     return TRUE;
643 }
644 
645 void
drmmode_set_dpms(ScrnInfoPtr scrn,int dpms,int flags)646 drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
647 {
648     modesettingPtr ms = modesettingPTR(scrn);
649     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
650     drmModeAtomicReq *req = drmModeAtomicAlloc();
651     uint32_t mode_flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
652     int ret = 0;
653     int i;
654 
655     assert(ms->atomic_modeset);
656 
657     if (!req)
658         return;
659 
660     for (i = 0; i < xf86_config->num_output; i++) {
661         xf86OutputPtr output = xf86_config->output[i];
662         drmmode_output_private_ptr drmmode_output = output->driver_private;
663 
664         if (output->crtc != NULL)
665             continue;
666 
667         ret = connector_add_prop(req, drmmode_output,
668                                  DRMMODE_CONNECTOR_CRTC_ID, 0);
669     }
670 
671     for (i = 0; i < xf86_config->num_crtc; i++) {
672         xf86CrtcPtr crtc = xf86_config->crtc[i];
673         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
674         Bool active = FALSE;
675 
676         ret |= crtc_add_dpms_props(req, crtc, dpms, &active);
677 
678         if (dpms == DPMSModeOn && active && drmmode_crtc->need_modeset) {
679             uint32_t fb_id;
680             int x, y;
681 
682             if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
683                 continue;
684             ret |= plane_add_props(req, crtc, fb_id, x, y);
685             drmmode_crtc->need_modeset = FALSE;
686         }
687     }
688 
689     if (ret == 0)
690         drmModeAtomicCommit(ms->fd, req, mode_flags, NULL);
691     drmModeAtomicFree(req);
692 
693     ms->pending_modeset = TRUE;
694     xf86DPMSSet(scrn, dpms, flags);
695     ms->pending_modeset = FALSE;
696 }
697 
698 static int
drmmode_output_dpms_atomic(xf86OutputPtr output,int mode)699 drmmode_output_dpms_atomic(xf86OutputPtr output, int mode)
700 {
701     modesettingPtr ms = modesettingPTR(output->scrn);
702     drmmode_output_private_ptr drmmode_output = output->driver_private;
703     xf86CrtcPtr crtc = drmmode_output->current_crtc;
704     drmModeAtomicReq *req;
705     uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
706     int ret = 0;
707 
708     if (mode == DPMSModeOn && !crtc)
709         return 1;
710 
711     assert(ms->atomic_modeset);
712 
713     req = drmModeAtomicAlloc();
714     if (!req)
715         return 1;
716 
717     if (crtc)
718         ret |= crtc_add_dpms_props(req, crtc, mode, NULL);
719 
720     if (mode == DPMSModeOn) {
721         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
722         drmModeModeInfo kmode;
723 
724         drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
725         ret |= drm_mode_ensure_blob(crtc, kmode);
726 
727         ret |= connector_add_prop(req, drmmode_output,
728                                   DRMMODE_CONNECTOR_CRTC_ID,
729                                   drmmode_crtc->mode_crtc->crtc_id);
730         ret |= crtc_add_prop(req, drmmode_crtc,
731                              DRMMODE_CRTC_ACTIVE, 1);
732         ret |= crtc_add_prop(req, drmmode_crtc,
733                              DRMMODE_CRTC_MODE_ID,
734                              drmmode_crtc->current_mode->blob_id);
735     } else {
736         ret |= connector_add_prop(req, drmmode_output,
737                                   DRMMODE_CONNECTOR_CRTC_ID, 0);
738     }
739 
740     if (ret == 0)
741         ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
742 
743     drmModeAtomicFree(req);
744     return ret;
745 }
746 
747 static int
drmmode_crtc_disable(xf86CrtcPtr crtc)748 drmmode_crtc_disable(xf86CrtcPtr crtc)
749 {
750     modesettingPtr ms = modesettingPTR(crtc->scrn);
751     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
752     drmModeAtomicReq *req = drmModeAtomicAlloc();
753     uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
754     int ret = 0;
755 
756     assert(ms->atomic_modeset);
757 
758     if (!req)
759         return 1;
760 
761     ret |= crtc_add_prop(req, drmmode_crtc,
762                          DRMMODE_CRTC_ACTIVE, 0);
763     ret |= crtc_add_prop(req, drmmode_crtc,
764                          DRMMODE_CRTC_MODE_ID, 0);
765 
766     if (ret == 0)
767         ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
768 
769     drmModeAtomicFree(req);
770     return ret;
771 }
772 
773 static Bool
drmmode_crtc_connected(xf86CrtcPtr crtc)774 drmmode_crtc_connected(xf86CrtcPtr crtc)
775 {
776     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
777     int i;
778 
779     for (i = 0; i < xf86_config->num_output; i++) {
780         xf86OutputPtr output = xf86_config->output[i];
781         drmmode_output_private_ptr drmmode_output;
782         drmmode_output = output->driver_private;
783 
784         if (output->crtc != crtc)
785             continue;
786 
787         if (drmmode_output->status == XF86OutputStatusConnected)
788             return TRUE;
789     }
790 
791     return FALSE;
792 }
793 
794 static int
drmmode_crtc_modeset(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t x,uint32_t y,uint32_t * output_ids,int output_count,drmModeModeInfoPtr mode)795 drmmode_crtc_modeset(xf86CrtcPtr crtc, uint32_t fb_id,
796                      uint32_t x, uint32_t y, uint32_t *output_ids,
797                      int output_count, drmModeModeInfoPtr mode)
798 {
799     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
800     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
801     drmmode_ptr drmmode = drmmode_crtc->drmmode;
802     struct dumb_bo *bo = NULL;
803     uint32_t new_fb_id = 0;
804     int sx, sy, sw, sh, dx, dy, dw, dh;
805     int ret, i;
806 
807     sx = x;
808     sy = y;
809 
810     if (crtc->driverIsPerformingTransform & XF86DriverTransformOutput) {
811         struct pixman_f_vector point;
812         int x1, y1, x2, y2;
813 
814         point.v[2] = 1;
815 
816         /* Convert output's area to framebuffer's area */
817         point.v[0] = 0;
818         point.v[1] = 0;
819         pixman_f_transform_point(&crtc->f_crtc_to_framebuffer, &point);
820         x2 = floor(point.v[0]);
821         y2 = floor(point.v[1]);
822 
823         point.v[0] = crtc->mode.HDisplay;
824         point.v[1] = crtc->mode.VDisplay;
825         pixman_f_transform_point(&crtc->f_crtc_to_framebuffer, &point);
826         x1 = floor(point.v[0]);
827         y1 = floor(point.v[1]);
828 
829         sw = max(x1, x2) - sx;
830         sh = max(y1, y2) - sy;
831 
832         /* Convert framebuffer's area to output's area */
833         point.v[0] = sx;
834         point.v[1] = sy;
835         pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &point);
836         x1 = floor(point.v[0]);
837         y1 = floor(point.v[1]);
838 
839         point.v[0] = sw;
840         point.v[1] = sh;
841         pixman_f_transform_point(&crtc->f_framebuffer_to_crtc, &point);
842         x2 = floor(point.v[0]);
843         y2 = floor(point.v[1]);
844 
845         dx = min(x1, x2) * mode->hdisplay / crtc->mode.HDisplay;
846         dy = min(y1, y2) * mode->vdisplay / crtc->mode.VDisplay;
847         dw = mode->hdisplay - dx;
848         dh = mode->vdisplay - dy;
849     } else {
850         sw = crtc->mode.HDisplay;
851         sh = crtc->mode.VDisplay;
852         dx = 0;
853         dy = 0;
854         dw = mode->hdisplay;
855         dh = mode->vdisplay;
856     }
857 
858     for (i = 0; i < xf86_config->num_output; i++) {
859         xf86OutputPtr output = xf86_config->output[i];
860         drmmode_output_private_ptr drmmode_output;
861 
862         if (output->crtc != crtc)
863             continue;
864 
865         /* NOTE: Only use the first output's padding */
866         drmmode_output = output->driver_private;
867         if (!output_count || drmmode_output->output_id != output_ids[0])
868             continue;
869 
870         dx += drmmode_output->padding_top;
871         dw -= drmmode_output->padding_top;
872         dw -= drmmode_output->padding_bottom;
873         dy += drmmode_output->padding_left;
874         dh -= drmmode_output->padding_left;
875         dh -= drmmode_output->padding_right;
876         break;
877     }
878 
879     /* prefer using the original FB */
880     ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
881                          fb_id, x, y, output_ids, output_count, mode);
882     if (!ret)
883         goto set_plane;
884 
885     /* fallback to a new dummy FB */
886     bo = dumb_bo_create(drmmode->fd, mode->hdisplay, mode->vdisplay,
887                         drmmode->kbpp);
888     if (!bo)
889         goto out;
890 
891     ret = drmModeAddFB(drmmode->fd, mode->hdisplay, mode->vdisplay,
892                        drmmode->scrn->depth, drmmode->kbpp,
893                        bo->pitch, bo->handle, &new_fb_id);
894     if (ret < 0)
895         goto out;
896 
897     ret = drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
898                          new_fb_id, 0, 0, output_ids, output_count, mode);
899     if (ret < 0)
900         goto out;
901 
902 set_plane:
903     ret = drmModeSetPlane(drmmode->fd, drmmode_crtc->plane_id,
904                           drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
905                           dx, dy, dw, dh,
906                           sx << 16, sy << 16, sw << 16, sh << 16);
907     if (ret < 0)
908         goto out;
909 
910     ret = 0;
911 out:
912     if (new_fb_id)
913         drmModeRmFB(drmmode->fd, new_fb_id);
914 
915     if (bo)
916         dumb_bo_destroy(drmmode->fd, bo);
917     return ret;
918 }
919 
920 static int
drmmode_crtc_set_mode(xf86CrtcPtr crtc,Bool test_only)921 drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only)
922 {
923     modesettingPtr ms = modesettingPTR(crtc->scrn);
924     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
925     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
926     drmmode_ptr drmmode = drmmode_crtc->drmmode;
927     ScreenPtr screen = crtc->scrn->pScreen;
928     drmModeModeInfo kmode;
929     int output_count = 0;
930     uint32_t *output_ids = NULL;
931     uint32_t fb_id;
932     int x, y;
933     int i, ret = 0;
934 
935     if (!drmmode_crtc_get_fb_id(crtc, &fb_id, &x, &y))
936         return 1;
937 
938 #ifdef GLAMOR_HAS_GBM
939     /* Make sure any pending drawing will be visible in a new scanout buffer */
940     if (drmmode->glamor)
941         glamor_finish(screen);
942 #endif
943 
944     if (ms->atomic_modeset) {
945         drmModeAtomicReq *req = drmModeAtomicAlloc();
946         Bool active;
947         uint32_t flags = DRM_MODE_ATOMIC_ALLOW_MODESET;
948 
949         if (!req)
950             return 1;
951 
952         ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
953         ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
954 
955         /* Orphaned CRTCs need to be disabled right now in atomic mode */
956         for (i = 0; i < xf86_config->num_crtc; i++) {
957             xf86CrtcPtr other_crtc = xf86_config->crtc[i];
958             drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private;
959             int lost_outputs = 0;
960             int remaining_outputs = 0;
961             int j;
962 
963             if (other_crtc == crtc)
964                 continue;
965 
966             for (j = 0; j < xf86_config->num_output; j++) {
967                 xf86OutputPtr output = xf86_config->output[j];
968                 drmmode_output_private_ptr drmmode_output = output->driver_private;
969 
970                 if (drmmode_output->current_crtc == other_crtc) {
971                     if (output->crtc == crtc)
972                         lost_outputs++;
973                     else
974                         remaining_outputs++;
975                 }
976             }
977 
978             if (lost_outputs > 0 && remaining_outputs == 0) {
979                 ret |= crtc_add_prop(req, other_drmmode_crtc,
980                                      DRMMODE_CRTC_ACTIVE, 0);
981                 ret |= crtc_add_prop(req, other_drmmode_crtc,
982                                      DRMMODE_CRTC_MODE_ID, 0);
983             }
984         }
985 
986         if (test_only)
987             flags |= DRM_MODE_ATOMIC_TEST_ONLY;
988 
989         if (ret == 0)
990             ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
991 
992         if (ret == 0 && !test_only) {
993             for (i = 0; i < xf86_config->num_output; i++) {
994                 xf86OutputPtr output = xf86_config->output[i];
995                 drmmode_output_private_ptr drmmode_output = output->driver_private;
996 
997                 if (output->crtc == crtc)
998                     drmmode_output->current_crtc = crtc;
999                 else if (drmmode_output->current_crtc == crtc)
1000                     drmmode_output->current_crtc = NULL;
1001             }
1002         }
1003 
1004         drmModeAtomicFree(req);
1005         return ret;
1006     }
1007 
1008     output_ids = calloc(sizeof(uint32_t), xf86_config->num_output);
1009     if (!output_ids)
1010         return -1;
1011 
1012     for (i = 0; i < xf86_config->num_output; i++) {
1013         xf86OutputPtr output = xf86_config->output[i];
1014         drmmode_output_private_ptr drmmode_output;
1015 
1016         if (output->crtc != crtc)
1017             continue;
1018 
1019         drmmode_output = output->driver_private;
1020         if (drmmode_output->output_id == -1)
1021             continue;
1022         output_ids[output_count] = drmmode_output->output_id;
1023         output_count++;
1024     }
1025 
1026     drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1027 
1028     ret = drmmode_crtc_modeset(crtc, fb_id, x, y,
1029                                output_ids, output_count, &kmode);
1030 
1031     free(output_ids);
1032     return ret;
1033 }
1034 
1035 int
drmmode_crtc_flip(xf86CrtcPtr crtc,uint32_t fb_id,uint32_t flags,void * data)1036 drmmode_crtc_flip(xf86CrtcPtr crtc, uint32_t fb_id, uint32_t flags, void *data)
1037 {
1038     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1039     modesettingPtr ms = modesettingPTR(crtc->scrn);
1040     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1041     int ret, i, sx, sy, sw, sh, dx, dy, dw, dh;
1042     drmModeModeInfo kmode;
1043 
1044     drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1045 
1046     if (fb_id == ms->drmmode.fb_id) {
1047         /* screen FB flip */
1048         sx = crtc->x;
1049         sy = crtc->y;
1050     } else {
1051         /* single crtc FB flip */
1052         sx = sy = 0;
1053     }
1054 
1055     sw = crtc->mode.HDisplay;
1056     sh = crtc->mode.VDisplay;
1057     dx = dy = 0;
1058     dw = kmode.hdisplay;
1059     dh = kmode.vdisplay;
1060 
1061     for (i = 0; i < xf86_config->num_output; i++) {
1062         xf86OutputPtr output = xf86_config->output[i];
1063         drmmode_output_private_ptr drmmode_output;
1064 
1065         if (output->crtc != crtc)
1066             continue;
1067 
1068         drmmode_output = output->driver_private;
1069         if (drmmode_output->output_id == -1)
1070             continue;
1071 
1072         /* NOTE: Only use the first output's padding */
1073         dx += drmmode_output->padding_top;
1074         dw -= drmmode_output->padding_top;
1075         dw -= drmmode_output->padding_bottom;
1076         dy += drmmode_output->padding_left;
1077         dh -= drmmode_output->padding_left;
1078         dh -= drmmode_output->padding_right;
1079         break;
1080     }
1081 
1082     ret = drmModeSetPlane(ms->fd, drmmode_crtc->plane_id,
1083                           drmmode_crtc->mode_crtc->crtc_id, fb_id, 0,
1084                           dx, dy, dw, dh,
1085                           sx << 16, sy << 16, sw << 16, sh << 16);
1086     if (ret)
1087         return ret;
1088 
1089     return drmModePageFlip(ms->fd, drmmode_crtc->mode_crtc->crtc_id,
1090                            fb_id, flags, data);
1091 }
1092 
1093 int
drmmode_bo_destroy(drmmode_ptr drmmode,drmmode_bo * bo)1094 drmmode_bo_destroy(drmmode_ptr drmmode, drmmode_bo *bo)
1095 {
1096     int ret;
1097 
1098 #ifdef GLAMOR_HAS_GBM
1099     if (bo->gbm) {
1100 #ifdef GLAMOR_HAS_GBM_MAP
1101         if (bo->gbm_ptr) {
1102             gbm_bo_unmap(bo->gbm, bo->gbm_map_data);
1103             bo->gbm_ptr = NULL;
1104         }
1105 #endif
1106 
1107         if (bo->owned_gbm)
1108             gbm_bo_destroy(bo->gbm);
1109 
1110         bo->gbm = NULL;
1111     }
1112 #endif
1113 
1114     if (bo->dumb) {
1115         ret = dumb_bo_destroy(drmmode->fd, bo->dumb);
1116         if (ret == 0)
1117             bo->dumb = NULL;
1118     }
1119 
1120     return 0;
1121 }
1122 
1123 uint32_t
drmmode_bo_get_pitch(drmmode_bo * bo)1124 drmmode_bo_get_pitch(drmmode_bo *bo)
1125 {
1126 #ifdef GLAMOR_HAS_GBM
1127     if (bo->gbm)
1128         return gbm_bo_get_stride(bo->gbm);
1129 #endif
1130 
1131     return bo->dumb->pitch;
1132 }
1133 
1134 static Bool
drmmode_bo_has_bo(drmmode_bo * bo)1135 drmmode_bo_has_bo(drmmode_bo *bo)
1136 {
1137 #ifdef GLAMOR_HAS_GBM
1138     if (bo->gbm)
1139         return TRUE;
1140 #endif
1141 
1142     return bo->dumb != NULL;
1143 }
1144 
1145 uint32_t
drmmode_bo_get_handle(drmmode_bo * bo)1146 drmmode_bo_get_handle(drmmode_bo *bo)
1147 {
1148 #ifdef GLAMOR_HAS_GBM
1149     if (bo->gbm)
1150         return gbm_bo_get_handle(bo->gbm).u32;
1151 #endif
1152 
1153     return bo->dumb->handle;
1154 }
1155 
1156 static void *
drmmode_bo_map(drmmode_ptr drmmode,drmmode_bo * bo)1157 drmmode_bo_map(drmmode_ptr drmmode, drmmode_bo *bo)
1158 {
1159     int ret;
1160 
1161 #ifdef GLAMOR_HAS_GBM
1162     if (bo->gbm) {
1163 #ifdef GLAMOR_HAS_GBM_MAP
1164         uint32_t stride;
1165 
1166         if (bo->gbm_ptr)
1167             return bo->gbm_ptr;
1168 
1169         bo->gbm_ptr = gbm_bo_map(bo->gbm, 0, 0, bo->width, bo->height,
1170                                  GBM_BO_TRANSFER_READ_WRITE, &stride,
1171                                  &bo->gbm_map_data);
1172         return bo->gbm_ptr;
1173 #else
1174         return NULL;
1175 #endif
1176     }
1177 #endif
1178 
1179     if (bo->dumb->ptr)
1180         return bo->dumb->ptr;
1181 
1182     ret = dumb_bo_map(drmmode->fd, bo->dumb);
1183     if (ret)
1184         return NULL;
1185 
1186     return bo->dumb->ptr;
1187 }
1188 
1189 int
drmmode_bo_import(drmmode_ptr drmmode,drmmode_bo * bo,uint32_t * fb_id)1190 drmmode_bo_import(drmmode_ptr drmmode, drmmode_bo *bo,
1191                   uint32_t *fb_id)
1192 {
1193 #ifdef GBM_BO_WITH_MODIFIERS
1194     modesettingPtr ms = modesettingPTR(drmmode->scrn);
1195     if (bo->gbm && ms->kms_has_modifiers &&
1196         gbm_bo_get_modifier(bo->gbm) != DRM_FORMAT_MOD_INVALID) {
1197         int num_fds;
1198 
1199         num_fds = gbm_bo_get_plane_count(bo->gbm);
1200         if (num_fds > 0) {
1201             int i;
1202             uint32_t format;
1203             uint32_t handles[4];
1204             uint32_t strides[4];
1205             uint32_t offsets[4];
1206             uint64_t modifiers[4];
1207 
1208             memset(handles, 0, sizeof(handles));
1209             memset(strides, 0, sizeof(strides));
1210             memset(offsets, 0, sizeof(offsets));
1211             memset(modifiers, 0, sizeof(modifiers));
1212 
1213             format = gbm_bo_get_format(bo->gbm);
1214             format = get_opaque_format(format);
1215             for (i = 0; i < num_fds; i++) {
1216                 handles[i] = gbm_bo_get_handle_for_plane(bo->gbm, i).u32;
1217                 strides[i] = gbm_bo_get_stride_for_plane(bo->gbm, i);
1218                 offsets[i] = gbm_bo_get_offset(bo->gbm, i);
1219                 modifiers[i] = gbm_bo_get_modifier(bo->gbm);
1220             }
1221 
1222             return drmModeAddFB2WithModifiers(drmmode->fd, bo->width, bo->height,
1223                                               format, handles, strides,
1224                                               offsets, modifiers, fb_id,
1225                                               DRM_MODE_FB_MODIFIERS);
1226         }
1227     }
1228 #endif
1229     return drmModeAddFB(drmmode->fd, bo->width, bo->height,
1230                         drmmode->scrn->depth, drmmode->kbpp,
1231                         drmmode_bo_get_pitch(bo),
1232                         drmmode_bo_get_handle(bo), fb_id);
1233 }
1234 
1235 static Bool
drmmode_create_bo(drmmode_ptr drmmode,drmmode_bo * bo,unsigned width,unsigned height,unsigned bpp)1236 drmmode_create_bo(drmmode_ptr drmmode, drmmode_bo *bo,
1237                   unsigned width, unsigned height, unsigned bpp)
1238 {
1239     bo->width = width;
1240     bo->height = height;
1241 
1242 #ifdef GLAMOR_HAS_GBM
1243     if (drmmode->glamor) {
1244         uint32_t format;
1245 
1246         switch (drmmode->scrn->depth) {
1247         case 15:
1248             format = GBM_FORMAT_ARGB1555;
1249             break;
1250         case 16:
1251             format = GBM_FORMAT_RGB565;
1252             break;
1253         case 30:
1254             format = GBM_FORMAT_ARGB2101010;
1255             break;
1256         default:
1257             format = GBM_FORMAT_ARGB8888;
1258             break;
1259         }
1260 
1261 #ifdef GBM_BO_WITH_MODIFIERS
1262         uint32_t num_modifiers;
1263         uint64_t *modifiers = NULL;
1264 
1265         num_modifiers = get_modifiers_set(drmmode->scrn, format, &modifiers,
1266                                           FALSE, TRUE);
1267         if (num_modifiers > 0 &&
1268             !(num_modifiers == 1 && modifiers[0] == DRM_FORMAT_MOD_INVALID)) {
1269             bo->gbm = gbm_bo_create_with_modifiers(drmmode->gbm, width, height,
1270                                                    format, modifiers,
1271                                                    num_modifiers);
1272             free(modifiers);
1273             if (bo->gbm) {
1274                 bo->used_modifiers = TRUE;
1275                 return TRUE;
1276             }
1277         }
1278 #endif
1279 
1280         bo->gbm = gbm_bo_create(drmmode->gbm, width, height, format,
1281                                 GBM_BO_USE_RENDERING | GBM_BO_USE_SCANOUT);
1282         bo->gbm_ptr = NULL;
1283         bo->used_modifiers = FALSE;
1284         bo->owned_gbm = TRUE;
1285         return bo->gbm != NULL;
1286     }
1287 #endif
1288 
1289     bo->dumb = dumb_bo_create(drmmode->fd, width, height, bpp);
1290     return bo->dumb != NULL;
1291 }
1292 
1293 Bool
drmmode_SetSlaveBO(PixmapPtr ppix,drmmode_ptr drmmode,int fd_handle,int pitch,int size)1294 drmmode_SetSlaveBO(PixmapPtr ppix,
1295                    drmmode_ptr drmmode, int fd_handle, int pitch, int size)
1296 {
1297     msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1298 
1299     if (fd_handle == -1) {
1300         dumb_bo_destroy(drmmode->fd, ppriv->backing_bo);
1301         ppriv->backing_bo = NULL;
1302         return TRUE;
1303     }
1304 
1305     ppriv->backing_bo =
1306         dumb_get_bo_from_fd(drmmode->fd, fd_handle, pitch, size);
1307     if (!ppriv->backing_bo)
1308         return FALSE;
1309 
1310     close(fd_handle);
1311     return TRUE;
1312 }
1313 
1314 static Bool
drmmode_SharedPixmapPresent(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1315 drmmode_SharedPixmapPresent(PixmapPtr ppix, xf86CrtcPtr crtc,
1316                             drmmode_ptr drmmode)
1317 {
1318     ScreenPtr master = crtc->randr_crtc->pScreen->current_master;
1319 
1320     if (master->PresentSharedPixmap(ppix)) {
1321         /* Success, queue flip to back target */
1322         if (drmmode_SharedPixmapFlip(ppix, crtc, drmmode))
1323             return TRUE;
1324 
1325         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
1326                    "drmmode_SharedPixmapFlip() failed, trying again next vblank\n");
1327 
1328         return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1329     }
1330 
1331     /* Failed to present, try again on next vblank after damage */
1332     if (master->RequestSharedPixmapNotifyDamage) {
1333         msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1334 
1335         /* Set flag first in case we are immediately notified */
1336         ppriv->wait_for_damage = TRUE;
1337 
1338         if (master->RequestSharedPixmapNotifyDamage(ppix))
1339             return TRUE;
1340         else
1341             ppriv->wait_for_damage = FALSE;
1342     }
1343 
1344     /* Damage notification not available, just try again on vblank */
1345     return drmmode_SharedPixmapPresentOnVBlank(ppix, crtc, drmmode);
1346 }
1347 
1348 struct vblank_event_args {
1349     PixmapPtr frontTarget;
1350     PixmapPtr backTarget;
1351     xf86CrtcPtr crtc;
1352     drmmode_ptr drmmode;
1353     Bool flip;
1354 };
1355 static void
drmmode_SharedPixmapVBlankEventHandler(uint64_t frame,uint64_t usec,void * data)1356 drmmode_SharedPixmapVBlankEventHandler(uint64_t frame, uint64_t usec,
1357                                        void *data)
1358 {
1359     struct vblank_event_args *args = data;
1360 
1361     drmmode_crtc_private_ptr drmmode_crtc = args->crtc->driver_private;
1362 
1363     if (args->flip) {
1364         /* frontTarget is being displayed, update crtc to reflect */
1365         drmmode_crtc->prime_pixmap = args->frontTarget;
1366         drmmode_crtc->prime_pixmap_back = args->backTarget;
1367 
1368         /* Safe to present on backTarget, no longer displayed */
1369         drmmode_SharedPixmapPresent(args->backTarget, args->crtc, args->drmmode);
1370     } else {
1371         /* backTarget is still being displayed, present on frontTarget */
1372         drmmode_SharedPixmapPresent(args->frontTarget, args->crtc, args->drmmode);
1373     }
1374 
1375     free(args);
1376 }
1377 
1378 static void
drmmode_SharedPixmapVBlankEventAbort(void * data)1379 drmmode_SharedPixmapVBlankEventAbort(void *data)
1380 {
1381     struct vblank_event_args *args = data;
1382 
1383     msGetPixmapPriv(args->drmmode, args->frontTarget)->flip_seq = 0;
1384 
1385     free(args);
1386 }
1387 
1388 Bool
drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix,xf86CrtcPtr crtc,drmmode_ptr drmmode)1389 drmmode_SharedPixmapPresentOnVBlank(PixmapPtr ppix, xf86CrtcPtr crtc,
1390                                     drmmode_ptr drmmode)
1391 {
1392     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1393     msPixmapPrivPtr ppriv = msGetPixmapPriv(drmmode, ppix);
1394     struct vblank_event_args *event_args;
1395 
1396     if (ppix == drmmode_crtc->prime_pixmap)
1397         return FALSE; /* Already flipped to this pixmap */
1398     if (ppix != drmmode_crtc->prime_pixmap_back)
1399         return FALSE; /* Pixmap is not a scanout pixmap for CRTC */
1400 
1401     event_args = calloc(1, sizeof(*event_args));
1402     if (!event_args)
1403         return FALSE;
1404 
1405     event_args->frontTarget = ppix;
1406     event_args->backTarget = drmmode_crtc->prime_pixmap;
1407     event_args->crtc = crtc;
1408     event_args->drmmode = drmmode;
1409     event_args->flip = FALSE;
1410 
1411     ppriv->flip_seq =
1412         ms_drm_queue_alloc(crtc, event_args,
1413                            drmmode_SharedPixmapVBlankEventHandler,
1414                            drmmode_SharedPixmapVBlankEventAbort);
1415 
1416     return ms_queue_vblank(crtc, MS_QUEUE_RELATIVE, 1, NULL, ppriv->flip_seq);
1417 }
1418 
1419 Bool
drmmode_SharedPixmapFlip(PixmapPtr frontTarget,xf86CrtcPtr crtc,drmmode_ptr drmmode)1420 drmmode_SharedPixmapFlip(PixmapPtr frontTarget, xf86CrtcPtr crtc,
1421                          drmmode_ptr drmmode)
1422 {
1423     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1424     msPixmapPrivPtr ppriv_front = msGetPixmapPriv(drmmode, frontTarget);
1425 
1426     struct vblank_event_args *event_args;
1427 
1428     event_args = calloc(1, sizeof(*event_args));
1429     if (!event_args)
1430         return FALSE;
1431 
1432     event_args->frontTarget = frontTarget;
1433     event_args->backTarget = drmmode_crtc->prime_pixmap;
1434     event_args->crtc = crtc;
1435     event_args->drmmode = drmmode;
1436     event_args->flip = TRUE;
1437 
1438     ppriv_front->flip_seq =
1439         ms_drm_queue_alloc(crtc, event_args,
1440                            drmmode_SharedPixmapVBlankEventHandler,
1441                            drmmode_SharedPixmapVBlankEventAbort);
1442 
1443     if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1444                         ppriv_front->fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1445                         (void *)(intptr_t) ppriv_front->flip_seq) < 0) {
1446         ms_drm_abort_seq(crtc->scrn, ppriv_front->flip_seq);
1447         return FALSE;
1448     }
1449 
1450     return TRUE;
1451 }
1452 
1453 static Bool
drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1454 drmmode_InitSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1455 {
1456     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1457 
1458     if (!drmmode_crtc->enable_flipping)
1459         return FALSE;
1460 
1461     if (drmmode_crtc->flipping_active)
1462         return TRUE;
1463 
1464     drmmode_crtc->flipping_active =
1465         drmmode_SharedPixmapPresent(drmmode_crtc->prime_pixmap_back,
1466                                     crtc, drmmode);
1467 
1468     return drmmode_crtc->flipping_active;
1469 }
1470 
1471 static void
drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1472 drmmode_FiniSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1473 {
1474     uint32_t seq;
1475     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1476 
1477     if (!drmmode_crtc->flipping_active)
1478         return;
1479 
1480     drmmode_crtc->flipping_active = FALSE;
1481 
1482     /* Abort page flip event handler on prime_pixmap */
1483     seq = msGetPixmapPriv(drmmode, drmmode_crtc->prime_pixmap)->flip_seq;
1484     if (seq)
1485         ms_drm_abort_seq(crtc->scrn, seq);
1486 
1487     /* Abort page flip event handler on prime_pixmap_back */
1488     seq = msGetPixmapPriv(drmmode,
1489                           drmmode_crtc->prime_pixmap_back)->flip_seq;
1490     if (seq)
1491         ms_drm_abort_seq(crtc->scrn, seq);
1492 }
1493 
1494 static Bool drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
1495                                               PixmapPtr *target);
1496 
1497 Bool
drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode,PixmapPtr front,PixmapPtr back)1498 drmmode_EnableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode,
1499                                    PixmapPtr front, PixmapPtr back)
1500 {
1501     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1502     ScrnInfoPtr scrn = crtc->scrn;
1503     modesettingPtr ms = modesettingPTR(scrn);
1504 
1505     drmmode_crtc->enable_flipping = TRUE;
1506 
1507     /* Set front scanout pixmap */
1508     drmmode_crtc->enable_flipping &=
1509         drmmode_set_target_scanout_pixmap(crtc, front,
1510                                           &drmmode_crtc->prime_pixmap);
1511     if (!drmmode_crtc->enable_flipping)
1512         return FALSE;
1513 
1514     /* Set back scanout pixmap */
1515     drmmode_crtc->enable_flipping &=
1516         drmmode_set_target_scanout_pixmap(crtc, back,
1517                                           &drmmode_crtc->prime_pixmap_back);
1518     if (!drmmode_crtc->enable_flipping) {
1519         drmmode_set_target_scanout_pixmap(crtc, NULL,
1520                                           &drmmode_crtc->prime_pixmap);
1521         return FALSE;
1522     }
1523 
1524     drmmode_set_desired_modes(scrn, &ms->drmmode, TRUE, TRUE);
1525 
1526     return TRUE;
1527 }
1528 
1529 void
drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc,drmmode_ptr drmmode)1530 drmmode_DisableSharedPixmapFlipping(xf86CrtcPtr crtc, drmmode_ptr drmmode)
1531 {
1532     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1533     ScrnInfoPtr scrn = crtc->scrn;
1534     modesettingPtr ms = modesettingPTR(scrn);
1535 
1536     drmmode_crtc->enable_flipping = FALSE;
1537 
1538     drmmode_FiniSharedPixmapFlipping(crtc, drmmode);
1539 
1540     drmmode_set_target_scanout_pixmap(crtc, NULL, &drmmode_crtc->prime_pixmap);
1541 
1542     drmmode_set_target_scanout_pixmap(crtc, NULL,
1543                                       &drmmode_crtc->prime_pixmap_back);
1544 
1545     drmmode_set_desired_modes(scrn, &ms->drmmode, TRUE, TRUE);
1546 }
1547 
1548 static void
drmmode_ConvertFromKMode(xf86OutputPtr output,drmModeModeInfo * kmode,DisplayModePtr mode)1549 drmmode_ConvertFromKMode(xf86OutputPtr output,
1550                          drmModeModeInfo * kmode, DisplayModePtr mode)
1551 {
1552     ScrnInfoPtr scrn = output->scrn;
1553     drmmode_output_private_ptr drmmode_output = output->driver_private;
1554 
1555     memset(mode, 0, sizeof(DisplayModeRec));
1556     mode->status = MODE_OK;
1557 
1558     mode->Clock = kmode->clock;
1559 
1560     mode->HDisplay = kmode->hdisplay;
1561     mode->HSyncStart = kmode->hsync_start;
1562     mode->HSyncEnd = kmode->hsync_end;
1563     mode->HTotal = kmode->htotal;
1564     mode->HSkew = kmode->hskew;
1565 
1566     mode->VDisplay = kmode->vdisplay;
1567     mode->VSyncStart = kmode->vsync_start;
1568     mode->VSyncEnd = kmode->vsync_end;
1569     mode->VTotal = kmode->vtotal;
1570     mode->VScan = kmode->vscan;
1571 
1572     mode->Flags = kmode->flags; //& FLAG_BITS;
1573     mode->name = strdup(kmode->name);
1574 
1575     if (kmode->type & DRM_MODE_TYPE_DRIVER)
1576         mode->type = M_T_DRIVER;
1577     if (kmode->type & DRM_MODE_TYPE_PREFERRED)
1578         mode->type |= M_T_PREFERRED;
1579     xf86SetModeCrtc(mode, scrn->adjustFlags);
1580 
1581     /* HACK: Use virtual size for all modes */
1582     if (drmmode_output->virtual_width && drmmode_output->virtual_height) {
1583         mode->HDisplay = drmmode_output->virtual_width;
1584         mode->VDisplay = drmmode_output->virtual_height;
1585     }
1586 }
1587 
1588 static void
drmmode_ConvertToKMode(xf86CrtcPtr crtc,drmModeModeInfo * kmode,DisplayModePtr mode)1589 drmmode_ConvertToKMode(xf86CrtcPtr crtc,
1590                        drmModeModeInfo * kmode, DisplayModePtr mode)
1591 {
1592     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1593     int i, j;
1594 
1595     /* HACK: Convert from virtual size */
1596     for (i = 0; i < xf86_config->num_output; i++) {
1597         xf86OutputPtr output = xf86_config->output[i];
1598         drmmode_output_private_ptr drmmode_output = output->driver_private;
1599         drmModeConnectorPtr koutput = drmmode_output->mode_output;
1600 
1601         if (output->crtc != crtc)
1602             continue;
1603 
1604         if (!drmmode_output->virtual_width || !drmmode_output->virtual_height)
1605             continue;
1606 
1607         /* Search for original mode */
1608         for (j = 0; j < koutput->count_modes; j++) {
1609             drmModeModeInfoPtr scan = &koutput->modes[j];
1610             if (scan->clock == mode->Clock &&
1611                 scan->hsync_start == mode->HSyncStart &&
1612                 scan->hsync_end == mode->HSyncEnd &&
1613                 scan->htotal == mode->HTotal &&
1614                 scan->hskew == mode->HSkew &&
1615                 scan->vsync_start == mode->VSyncStart &&
1616                 scan->vsync_end == mode->VSyncEnd &&
1617                 scan->vtotal == mode->VTotal &&
1618                 scan->vscan == mode->VScan) {
1619                 *kmode = *scan;
1620                 return;
1621             }
1622         }
1623     }
1624 
1625     memset(kmode, 0, sizeof(*kmode));
1626 
1627     kmode->clock = mode->Clock;
1628     kmode->hdisplay = mode->HDisplay;
1629     kmode->hsync_start = mode->HSyncStart;
1630     kmode->hsync_end = mode->HSyncEnd;
1631     kmode->htotal = mode->HTotal;
1632     kmode->hskew = mode->HSkew;
1633 
1634     kmode->vdisplay = mode->VDisplay;
1635     kmode->vsync_start = mode->VSyncStart;
1636     kmode->vsync_end = mode->VSyncEnd;
1637     kmode->vtotal = mode->VTotal;
1638     kmode->vscan = mode->VScan;
1639 
1640     kmode->flags = mode->Flags; //& FLAG_BITS;
1641     if (mode->name)
1642         strncpy(kmode->name, mode->name, DRM_DISPLAY_MODE_LEN);
1643     kmode->name[DRM_DISPLAY_MODE_LEN - 1] = 0;
1644 
1645 }
1646 
1647 static void
drmmode_crtc_dpms(xf86CrtcPtr crtc,int mode)1648 drmmode_crtc_dpms(xf86CrtcPtr crtc, int mode)
1649 {
1650     modesettingPtr ms = modesettingPTR(crtc->scrn);
1651     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1652     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1653 
1654     /* XXX Check if DPMS mode is already the right one */
1655 
1656     drmmode_crtc->dpms_mode = mode;
1657 
1658     if (ms->atomic_modeset) {
1659         if (mode != DPMSModeOn && !ms->pending_modeset)
1660             drmmode_crtc_disable(crtc);
1661     } else if (crtc->enabled == FALSE) {
1662         drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1663                        0, 0, 0, NULL, 0, NULL);
1664     }
1665 }
1666 
1667 static Bool
drmmode_crtc_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode,xf86CrtcPtr crtc)1668 drmmode_crtc_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
1669                      xf86CrtcPtr crtc)
1670 {
1671     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1672     PixmapPtr screen_pixmap = pScreen->GetScreenPixmap(pScreen);
1673     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1674     drmmode_prop_info_rec *props_plane = drmmode_crtc->props_plane;
1675     drmModeObjectProperties *props;
1676     PixmapPtr src = NULL, dst;
1677     drmModeFBPtr fbcon;
1678     struct dumb_bo *bo;
1679     GCPtr gc;
1680     int src_x, src_y, src_w, src_h, crtc_x, crtc_y, crtc_w, crtc_h;
1681     int fbcon_id, fb_width, fb_height, fb_pitch, fb_depth, fb_bpp;
1682     Bool ret = FALSE;
1683 
1684     if (!drmmode_crtc->plane_id)
1685         return FALSE;
1686 
1687     if (!(fbcon_id = drmmode_crtc->mode_crtc->buffer_id))
1688         return FALSE;
1689 
1690     if (fbcon_id == drmmode->fb_id) {
1691         /* in some rare case there might be no fbcon and we might already
1692          * be the one with the current fb to avoid a false deadlck in
1693          * kernel ttm code just do nothing as anyway there is nothing
1694          * to do
1695          */
1696         return FALSE;
1697     }
1698 
1699     props = drmModeObjectGetProperties(drmmode->fd, drmmode_crtc->plane_id,
1700                                        DRM_MODE_OBJECT_PLANE);
1701     if (!props) {
1702         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
1703                    "couldn't get plane properties\n");
1704         return FALSE;
1705     }
1706 
1707     src_x = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_X],
1708                                    props, 0) >> 16;
1709     src_y = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_Y],
1710                                    props, 0) >> 16;
1711     src_w = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_W],
1712                                    props, 0) >> 16;
1713     src_h = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_SRC_H],
1714                                    props, 0) >> 16;
1715     crtc_x = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_X],
1716                                     props, 0) + crtc->x;
1717     crtc_y = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_Y],
1718                                     props, 0) + crtc->y;
1719     crtc_w = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_W],
1720                                     props, 0);
1721     crtc_h = drmmode_prop_get_value(&props_plane[DRMMODE_PLANE_CRTC_H],
1722                                     props, 0);
1723     drmModeFreeObjectProperties(props);
1724 
1725     if (!src_w || !src_h || src_w != crtc_w || src_h != crtc_h ||
1726         crtc_x + crtc_w > screen_pixmap->drawable.width ||
1727         crtc_y + crtc_h > screen_pixmap->drawable.height)
1728         return FALSE;
1729 
1730     fbcon = drmModeGetFB(drmmode->fd, fbcon_id);
1731     if (!fbcon)
1732         return FALSE;
1733 
1734     fb_width = fbcon->width;
1735     fb_height = fbcon->height;
1736     fb_pitch = fbcon->pitch;
1737     fb_depth = fbcon->depth;
1738     fb_bpp = fbcon->bpp;
1739 
1740     bo = dumb_get_bo_from_handle(drmmode->fd, fbcon->handle, fbcon->pitch,
1741                                  fbcon->pitch * fbcon->height);
1742     drmModeFreeFB(fbcon);
1743     if (!bo)
1744         return FALSE;
1745 
1746     if (dumb_bo_map(drmmode->fd, bo) < 0)
1747         goto out;
1748 
1749     src = drmmode_create_pixmap_header(pScreen, fb_width,
1750                                        fb_height, fb_depth,
1751                                        fb_bpp, fb_pitch,
1752                                        bo->ptr);
1753     if (!src)
1754         goto out;
1755 
1756     if (drmmode->exa) {
1757         if (!ms_exa_set_pixmap_bo(pScrn, src, bo, FALSE))
1758             goto out;
1759     }
1760 #ifdef GLAMOR_HAS_GBM
1761     else if (drmmode->glamor) {
1762         if (!glamor_egl_create_textured_pixmap(src, bo->handle, bo->pitch))
1763             goto out;
1764     }
1765 #endif
1766 
1767     dst = pScreen->GetScreenPixmap(pScreen);
1768 
1769     gc = GetScratchGC(pScrn->depth, pScreen);
1770     ValidateGC(&dst->drawable, gc);
1771 
1772     (*gc->ops->CopyArea)(&src->drawable, &dst->drawable, gc, src_x, src_y,
1773                          src_w, src_h, crtc_x, crtc_y);
1774 
1775     FreeScratchGC(gc);
1776     ret = TRUE;
1777 
1778 out:
1779     if (src)
1780         pScreen->DestroyPixmap(src);
1781     if (bo)
1782         dumb_bo_destroy(drmmode->fd, bo);
1783     return ret;
1784 }
1785 
1786 void
drmmode_copy_fb(ScrnInfoPtr pScrn,drmmode_ptr drmmode)1787 drmmode_copy_fb(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
1788 {
1789     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
1790     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
1791     Bool ret = FALSE;
1792     int i;
1793 
1794     if (getenv("XSERVER_NO_BG_NONE"))
1795         return;
1796 
1797     for (i = 0; i < xf86_config->num_crtc; i++)
1798         ret |= drmmode_crtc_copy_fb(pScrn, drmmode, xf86_config->crtc[i]);
1799 
1800     if (!ret)
1801         return;
1802 
1803     pScreen->canDoBGNoneRoot = TRUE;
1804 }
1805 
1806 static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc,DisplayModePtr mode,Rotation rotation,int x,int y)1807 drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
1808                        Rotation rotation, int x, int y)
1809 {
1810     modesettingPtr ms = modesettingPTR(crtc->scrn);
1811     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1812     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1813     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1814     int saved_x, saved_y;
1815     Rotation saved_rotation;
1816     DisplayModeRec saved_mode;
1817     Bool ret = TRUE;
1818     Bool can_test;
1819     int i;
1820 
1821     /* Ignore modeset when disconnected in hotplug reset mode */
1822     if (drmmode->hotplug_reset && !drmmode_crtc_connected(crtc))
1823         return 0;
1824 
1825     saved_mode = crtc->mode;
1826     saved_x = crtc->x;
1827     saved_y = crtc->y;
1828     saved_rotation = crtc->rotation;
1829 
1830     if (mode) {
1831         crtc->mode = *mode;
1832         crtc->x = x;
1833         crtc->y = y;
1834         crtc->rotation = rotation;
1835 
1836         if (!drmmode_apply_transform(crtc))
1837             goto done;
1838 
1839         crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
1840                                crtc->gamma_blue, crtc->gamma_size);
1841 
1842         can_test = drmmode_crtc_can_test_mode(crtc);
1843         if (drmmode_crtc_set_mode(crtc, can_test)) {
1844             xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
1845                        "failed to set mode: %s\n", strerror(errno));
1846             ret = FALSE;
1847             goto done;
1848         } else
1849             ret = TRUE;
1850 
1851         if (crtc->scrn->pScreen)
1852             xf86CrtcSetScreenSubpixelOrder(crtc->scrn->pScreen);
1853 
1854         ms->pending_modeset = TRUE;
1855         drmmode_crtc->need_modeset = FALSE;
1856         crtc->funcs->dpms(crtc, DPMSModeOn);
1857 
1858         if (drmmode_crtc->prime_pixmap_back)
1859             drmmode_InitSharedPixmapFlipping(crtc, drmmode);
1860 
1861         /* go through all the outputs and force DPMS them back on? */
1862         for (i = 0; i < xf86_config->num_output; i++) {
1863             xf86OutputPtr output = xf86_config->output[i];
1864             drmmode_output_private_ptr drmmode_output;
1865 
1866             if (output->crtc != crtc)
1867                 continue;
1868 
1869             drmmode_output = output->driver_private;
1870             if (drmmode_output->output_id == -1)
1871                 continue;
1872             output->funcs->dpms(output, DPMSModeOn);
1873         }
1874 
1875         /* if we only tested the mode previously, really set it now */
1876         if (can_test)
1877             drmmode_crtc_set_mode(crtc, FALSE);
1878         ms->pending_modeset = FALSE;
1879     }
1880 
1881  done:
1882     if (!ret) {
1883         crtc->x = saved_x;
1884         crtc->y = saved_y;
1885         crtc->rotation = saved_rotation;
1886         crtc->mode = saved_mode;
1887     } else
1888         crtc->active = TRUE;
1889 
1890     return ret;
1891 }
1892 
1893 static void
drmmode_set_cursor_colors(xf86CrtcPtr crtc,int bg,int fg)1894 drmmode_set_cursor_colors(xf86CrtcPtr crtc, int bg, int fg)
1895 {
1896 
1897 }
1898 
1899 static void
drmmode_set_cursor_position(xf86CrtcPtr crtc,int x,int y)1900 drmmode_set_cursor_position(xf86CrtcPtr crtc, int x, int y)
1901 {
1902     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1903     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1904     drmModeModeInfo kmode;
1905 
1906     drmmode_ConvertToKMode(crtc, &kmode, &crtc->mode);
1907 
1908     x = x * crtc->mode.HDisplay / kmode.hdisplay;
1909     y = y * crtc->mode.VDisplay / kmode.vdisplay;
1910 
1911     drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
1912 }
1913 
1914 static Bool
drmmode_set_cursor(xf86CrtcPtr crtc)1915 drmmode_set_cursor(xf86CrtcPtr crtc)
1916 {
1917     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1918     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1919     uint32_t handle = drmmode_crtc->cursor_bo->handle;
1920     modesettingPtr ms = modesettingPTR(crtc->scrn);
1921     CursorPtr cursor = xf86CurrentCursor(crtc->scrn->pScreen);
1922     int ret = -EINVAL;
1923 
1924     if (cursor == NullCursor)
1925 	    return TRUE;
1926 
1927     ret = drmModeSetCursor2(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1928                             handle, ms->cursor_width, ms->cursor_height,
1929                             cursor->bits->xhot, cursor->bits->yhot);
1930 
1931     /* -EINVAL can mean that an old kernel supports drmModeSetCursor but
1932      * not drmModeSetCursor2, though it can mean other things too. */
1933     if (ret == -EINVAL)
1934         ret = drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
1935                                handle, ms->cursor_width, ms->cursor_height);
1936 
1937     /* -ENXIO normally means that the current drm driver supports neither
1938      * cursor_set nor cursor_set2.  Disable hardware cursor support for
1939      * the rest of the session in that case. */
1940     if (ret == -ENXIO) {
1941         xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
1942         xf86CursorInfoPtr cursor_info = xf86_config->cursor_info;
1943 
1944         cursor_info->MaxWidth = cursor_info->MaxHeight = 0;
1945         drmmode_crtc->drmmode->sw_cursor = TRUE;
1946     }
1947 
1948     if (ret)
1949         /* fallback to swcursor */
1950         return FALSE;
1951     return TRUE;
1952 }
1953 
1954 static void drmmode_hide_cursor(xf86CrtcPtr crtc);
1955 
1956 /*
1957  * The load_cursor_argb_check driver hook.
1958  *
1959  * Sets the hardware cursor by calling the drmModeSetCursor2 ioctl.
1960  * On failure, returns FALSE indicating that the X server should fall
1961  * back to software cursors.
1962  */
1963 static Bool
drmmode_load_cursor_argb_check(xf86CrtcPtr crtc,CARD32 * image)1964 drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 *image)
1965 {
1966     modesettingPtr ms = modesettingPTR(crtc->scrn);
1967     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1968     int i;
1969     uint32_t *ptr;
1970 
1971     /* cursor should be mapped already */
1972     ptr = (uint32_t *) (drmmode_crtc->cursor_bo->ptr);
1973 
1974     for (i = 0; i < ms->cursor_width * ms->cursor_height; i++)
1975         ptr[i] = image[i];      // cpu_to_le32(image[i]);
1976 
1977     if (drmmode_crtc->cursor_up)
1978         return drmmode_set_cursor(crtc);
1979     return TRUE;
1980 }
1981 
1982 static void
drmmode_hide_cursor(xf86CrtcPtr crtc)1983 drmmode_hide_cursor(xf86CrtcPtr crtc)
1984 {
1985     modesettingPtr ms = modesettingPTR(crtc->scrn);
1986     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1987     drmmode_ptr drmmode = drmmode_crtc->drmmode;
1988 
1989     drmmode_crtc->cursor_up = FALSE;
1990     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0,
1991                      ms->cursor_width, ms->cursor_height);
1992 }
1993 
1994 static Bool
drmmode_show_cursor(xf86CrtcPtr crtc)1995 drmmode_show_cursor(xf86CrtcPtr crtc)
1996 {
1997     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
1998     drmmode_crtc->cursor_up = TRUE;
1999     return drmmode_set_cursor(crtc);
2000 }
2001 
2002 static void
drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)2003 drmmode_set_gamma_lut(drmmode_crtc_private_ptr drmmode_crtc,
2004                       uint16_t * red, uint16_t * green, uint16_t * blue,
2005                       int size)
2006 {
2007     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2008     drmmode_prop_info_ptr gamma_lut_info =
2009         &drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT];
2010     const uint32_t crtc_id = drmmode_crtc->mode_crtc->crtc_id;
2011     uint32_t blob_id;
2012     struct drm_color_lut lut[size];
2013 
2014     assert(gamma_lut_info->prop_id != 0);
2015 
2016     for (int i = 0; i < size; i++) {
2017         lut[i].red = red[i];
2018         lut[i].green = green[i];
2019         lut[i].blue = blue[i];
2020     }
2021 
2022     if (drmModeCreatePropertyBlob(drmmode->fd, lut, sizeof(lut), &blob_id))
2023         return;
2024 
2025     drmModeObjectSetProperty(drmmode->fd, crtc_id, DRM_MODE_OBJECT_CRTC,
2026                              gamma_lut_info->prop_id, blob_id);
2027 
2028     drmModeDestroyPropertyBlob(drmmode->fd, blob_id);
2029 }
2030 
2031 static void
drmmode_crtc_gamma_set(xf86CrtcPtr crtc,uint16_t * red,uint16_t * green,uint16_t * blue,int size)2032 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
2033                        uint16_t * blue, int size)
2034 {
2035     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2036     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2037 
2038     if (drmmode_crtc->use_gamma_lut) {
2039         drmmode_set_gamma_lut(drmmode_crtc, red, green, blue, size);
2040     } else {
2041         drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
2042                             size, red, green, blue);
2043     }
2044 }
2045 
2046 static Bool
drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2047 drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
2048                                       PixmapPtr *target)
2049 {
2050     ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
2051     PixmapPtr screenpix = screen->GetScreenPixmap(screen);
2052     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
2053     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2054     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2055     int c, total_width = 0, max_height = 0, this_x = 0;
2056 
2057     if (*target) {
2058         PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
2059         if (drmmode->fb_id) {
2060             drmModeRmFB(drmmode->fd, drmmode->fb_id);
2061             drmmode->fb_id = 0;
2062         }
2063         drmmode_crtc->prime_pixmap_x = 0;
2064         *target = NULL;
2065     }
2066 
2067     if (!ppix)
2068         return TRUE;
2069 
2070     /* iterate over all the attached crtcs to work out the bounding box */
2071     for (c = 0; c < xf86_config->num_crtc; c++) {
2072         xf86CrtcPtr iter = xf86_config->crtc[c];
2073         if (!iter->enabled && iter != crtc)
2074             continue;
2075         if (iter == crtc) {
2076             this_x = total_width;
2077             total_width += ppix->drawable.width;
2078             if (max_height < ppix->drawable.height)
2079                 max_height = ppix->drawable.height;
2080         } else {
2081             total_width += iter->mode.HDisplay;
2082             if (max_height < iter->mode.VDisplay)
2083                 max_height = iter->mode.VDisplay;
2084         }
2085     }
2086 
2087     if (total_width != screenpix->drawable.width ||
2088         max_height != screenpix->drawable.height) {
2089 
2090         if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
2091             return FALSE;
2092 
2093         screenpix = screen->GetScreenPixmap(screen);
2094         screen->width = screenpix->drawable.width = total_width;
2095         screen->height = screenpix->drawable.height = max_height;
2096     }
2097     drmmode_crtc->prime_pixmap_x = this_x;
2098     PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
2099                              RR_Rotate_0);
2100     *target = ppix;
2101     return TRUE;
2102 }
2103 
2104 static Bool
drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2105 drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
2106                                       PixmapPtr *target)
2107 {
2108     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2109     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2110     msPixmapPrivPtr ppriv;
2111     void *ptr;
2112 
2113     if (*target) {
2114         ppriv = msGetPixmapPriv(drmmode, *target);
2115         drmModeRmFB(drmmode->fd, ppriv->fb_id);
2116         ppriv->fb_id = 0;
2117         if (ppriv->slave_damage) {
2118             DamageUnregister(ppriv->slave_damage);
2119             ppriv->slave_damage = NULL;
2120         }
2121         *target = NULL;
2122     }
2123 
2124     if (!ppix)
2125         return TRUE;
2126 
2127     ppriv = msGetPixmapPriv(drmmode, ppix);
2128     if (!ppriv->slave_damage) {
2129         ppriv->slave_damage = DamageCreate(NULL, NULL,
2130                                            DamageReportNone,
2131                                            TRUE,
2132                                            crtc->randr_crtc->pScreen,
2133                                            NULL);
2134     }
2135     ptr = drmmode_map_slave_bo(drmmode, ppriv);
2136     ppix->devPrivate.ptr = ptr;
2137     DamageRegister(&ppix->drawable, ppriv->slave_damage);
2138 
2139     if (ppriv->fb_id == 0) {
2140         drmModeAddFB(drmmode->fd, ppix->drawable.width,
2141                      ppix->drawable.height,
2142                      ppix->drawable.depth,
2143                      ppix->drawable.bitsPerPixel,
2144                      ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
2145     }
2146     *target = ppix;
2147     return TRUE;
2148 }
2149 
2150 static Bool
drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix,PixmapPtr * target)2151 drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
2152                                   PixmapPtr *target)
2153 {
2154     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2155     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2156 
2157     if (drmmode->reverse_prime_offload_mode)
2158         return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
2159     else
2160         return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
2161 }
2162 
2163 static Bool
drmmode_set_scanout_pixmap(xf86CrtcPtr crtc,PixmapPtr ppix)2164 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
2165 {
2166     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2167 
2168     /* Use DisableSharedPixmapFlipping before switching to single buf */
2169     if (drmmode_crtc->enable_flipping)
2170         return FALSE;
2171 
2172     return drmmode_set_target_scanout_pixmap(crtc, ppix,
2173                                              &drmmode_crtc->prime_pixmap);
2174 }
2175 
2176 static void
drmmode_clear_pixmap(PixmapPtr pixmap)2177 drmmode_clear_pixmap(PixmapPtr pixmap)
2178 {
2179     ScreenPtr screen = pixmap->drawable.pScreen;
2180     GCPtr gc;
2181 
2182     gc = GetScratchGC(pixmap->drawable.depth, screen);
2183     if (gc) {
2184         miClearDrawable(&pixmap->drawable, gc);
2185         FreeScratchGC(gc);
2186     }
2187 }
2188 
2189 static void *
drmmode_shadow_allocate(xf86CrtcPtr crtc,int width,int height)2190 drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
2191 {
2192     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2193     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2194     int ret;
2195 
2196     if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
2197                            width, height, drmmode->kbpp)) {
2198         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
2199                "Couldn't allocate shadow memory for rotated CRTC\n");
2200         return NULL;
2201     }
2202 
2203     ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
2204                             &drmmode_crtc->rotate_fb_id);
2205 
2206     if (ret) {
2207         ErrorF("failed to add rotate fb\n");
2208         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
2209         return NULL;
2210     }
2211 
2212 #ifdef GLAMOR_HAS_GBM
2213     if (drmmode->gbm)
2214         return drmmode_crtc->rotate_bo.gbm;
2215 #endif
2216     return drmmode_crtc->rotate_bo.dumb;
2217 }
2218 
2219 PixmapPtr
drmmode_create_pixmap_header(ScreenPtr pScreen,int width,int height,int depth,int bitsPerPixel,int devKind,void * pPixData)2220 drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
2221                              int depth, int bitsPerPixel, int devKind,
2222                              void *pPixData)
2223 {
2224     PixmapPtr pixmap;
2225 
2226     /* width and height of 0 means don't allocate any pixmap data */
2227     pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
2228 
2229     if (pixmap) {
2230         if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
2231                                            bitsPerPixel, devKind, pPixData))
2232             return pixmap;
2233         (*pScreen->DestroyPixmap)(pixmap);
2234     }
2235     return NullPixmap;
2236 }
2237 
2238 static Bool
2239 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
2240 
2241 static PixmapPtr
drmmode_shadow_create(xf86CrtcPtr crtc,void * data,int width,int height)2242 drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
2243 {
2244     ScrnInfoPtr scrn = crtc->scrn;
2245     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2246     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2247     uint32_t rotate_pitch;
2248     PixmapPtr rotate_pixmap;
2249     void *pPixData = NULL;
2250 
2251     if (!data) {
2252         data = drmmode_shadow_allocate(crtc, width, height);
2253         if (!data) {
2254             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2255                        "Couldn't allocate shadow pixmap for rotated CRTC\n");
2256             return NULL;
2257         }
2258     }
2259 
2260     if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
2261         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2262                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
2263         return NULL;
2264     }
2265 
2266     pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
2267     rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo),
2268 
2269     rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
2270                                                  width, height,
2271                                                  scrn->depth,
2272                                                  drmmode->kbpp,
2273                                                  rotate_pitch,
2274                                                  pPixData);
2275 
2276     if (rotate_pixmap == NULL) {
2277         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
2278                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
2279         return NULL;
2280     }
2281 
2282     drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
2283 
2284     return rotate_pixmap;
2285 }
2286 
2287 static void
drmmode_shadow_destroy(xf86CrtcPtr crtc,PixmapPtr rotate_pixmap,void * data)2288 drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
2289 {
2290     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2291     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2292 
2293     if (rotate_pixmap) {
2294         rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
2295     }
2296 
2297     if (data) {
2298         drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
2299         drmmode_crtc->rotate_fb_id = 0;
2300 
2301         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
2302         memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
2303     }
2304 }
2305 
2306 static void
drmmode_crtc_destroy(xf86CrtcPtr crtc)2307 drmmode_crtc_destroy(xf86CrtcPtr crtc)
2308 {
2309     drmmode_mode_ptr iterator, next;
2310     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2311     modesettingPtr ms = modesettingPTR(crtc->scrn);
2312 
2313     if (!ms->atomic_modeset)
2314         return;
2315 
2316     drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2317     xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
2318         drm_mode_destroy(crtc, iterator);
2319     }
2320 }
2321 
2322 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
2323     .dpms = drmmode_crtc_dpms,
2324     .set_mode_major = drmmode_set_mode_major,
2325     .set_cursor_colors = drmmode_set_cursor_colors,
2326     .set_cursor_position = drmmode_set_cursor_position,
2327     .show_cursor_check = drmmode_show_cursor,
2328     .hide_cursor = drmmode_hide_cursor,
2329     .load_cursor_argb_check = drmmode_load_cursor_argb_check,
2330 
2331     .gamma_set = drmmode_crtc_gamma_set,
2332     .destroy = drmmode_crtc_destroy,
2333     .set_scanout_pixmap = drmmode_set_scanout_pixmap,
2334     .shadow_allocate = drmmode_shadow_allocate,
2335     .shadow_create = drmmode_shadow_create,
2336     .shadow_destroy = drmmode_shadow_destroy,
2337 };
2338 
2339 static uint32_t
drmmode_crtc_vblank_pipe(int crtc_id)2340 drmmode_crtc_vblank_pipe(int crtc_id)
2341 {
2342     if (crtc_id > 1)
2343         return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
2344     else if (crtc_id > 0)
2345         return DRM_VBLANK_SECONDARY;
2346     else
2347         return 0;
2348 }
2349 
2350 static Bool
is_plane_assigned(ScrnInfoPtr scrn,int plane_id)2351 is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
2352 {
2353     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
2354     int c;
2355 
2356     for (c = 0; c < xf86_config->num_crtc; c++) {
2357         xf86CrtcPtr iter = xf86_config->crtc[c];
2358         drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
2359         if (drmmode_crtc->plane_id == plane_id)
2360             return TRUE;
2361     }
2362 
2363     return FALSE;
2364 }
2365 
2366 /**
2367  * Populates the formats array, and the modifiers of each format for a drm_plane.
2368  */
2369 static Bool
populate_format_modifiers(xf86CrtcPtr crtc,const drmModePlane * kplane,uint32_t blob_id)2370 populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
2371                           uint32_t blob_id)
2372 {
2373     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2374     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2375     unsigned i, j;
2376     drmModePropertyBlobRes *blob;
2377     struct drm_format_modifier_blob *fmt_mod_blob;
2378     uint32_t *blob_formats;
2379     struct drm_format_modifier *blob_modifiers;
2380 
2381     if (!blob_id)
2382         return FALSE;
2383 
2384     blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
2385     if (!blob)
2386         return FALSE;
2387 
2388     fmt_mod_blob = blob->data;
2389     blob_formats = formats_ptr(fmt_mod_blob);
2390     blob_modifiers = modifiers_ptr(fmt_mod_blob);
2391 
2392     assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
2393 
2394     for (i = 0; i < fmt_mod_blob->count_formats; i++) {
2395         uint32_t num_modifiers = 0;
2396         uint64_t *modifiers = NULL;
2397         uint64_t *tmp;
2398         for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
2399             struct drm_format_modifier *mod = &blob_modifiers[j];
2400 
2401             if ((i < mod->offset) || (i > mod->offset + 63))
2402                 continue;
2403             if (!(mod->formats & (1 << (i - mod->offset))))
2404                 continue;
2405 
2406             if (!mod->modifier || mod->modifier == DRM_FORMAT_MOD_INVALID)
2407                 continue;
2408 
2409             num_modifiers++;
2410             tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
2411             if (!tmp) {
2412                 free(modifiers);
2413                 drmModeFreePropertyBlob(blob);
2414                 return FALSE;
2415             }
2416             modifiers = tmp;
2417             modifiers[num_modifiers - 1] = mod->modifier;
2418         }
2419 
2420         drmmode_crtc->formats[i].format = blob_formats[i];
2421         drmmode_crtc->formats[i].modifiers = modifiers;
2422         drmmode_crtc->formats[i].num_modifiers = num_modifiers;
2423     }
2424 
2425     drmModeFreePropertyBlob(blob);
2426 
2427     return TRUE;
2428 }
2429 
2430 static void
drmmode_crtc_create_planes(xf86CrtcPtr crtc,int num)2431 drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
2432 {
2433     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
2434     drmmode_ptr drmmode = drmmode_crtc->drmmode;
2435     drmModePlaneRes *kplane_res;
2436     drmModePlane *kplane, *best_kplane = NULL;
2437     drmModeObjectProperties *props;
2438     uint32_t i, type, blob_id;
2439     int current_crtc, best_plane = 0;
2440 
2441     static drmmode_prop_enum_info_rec plane_type_enums[] = {
2442         [DRMMODE_PLANE_TYPE_PRIMARY] = {
2443             .name = "Primary",
2444         },
2445         [DRMMODE_PLANE_TYPE_OVERLAY] = {
2446             .name = "Overlay",
2447         },
2448         [DRMMODE_PLANE_TYPE_CURSOR] = {
2449             .name = "Cursor",
2450         },
2451     };
2452     static const drmmode_prop_info_rec plane_props[] = {
2453         [DRMMODE_PLANE_TYPE] = {
2454             .name = "type",
2455             .enum_values = plane_type_enums,
2456             .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
2457         },
2458         [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
2459         [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
2460         [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
2461         [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
2462         [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
2463         [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
2464         [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
2465         [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
2466         [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
2467         [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
2468         [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
2469     };
2470     drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
2471 
2472     if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
2473         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2474                    "failed to copy plane property info\n");
2475         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2476         return;
2477     }
2478 
2479     kplane_res = drmModeGetPlaneResources(drmmode->fd);
2480     if (!kplane_res) {
2481         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2482                    "failed to get plane resources: %s\n", strerror(errno));
2483         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2484         return;
2485     }
2486 
2487     for (i = 0; i < kplane_res->count_planes; i++) {
2488         int plane_id;
2489 
2490         kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
2491         if (!kplane)
2492             continue;
2493 
2494         if (!(kplane->possible_crtcs & (1 << num)) ||
2495             is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
2496             drmModeFreePlane(kplane);
2497             continue;
2498         }
2499 
2500         plane_id = kplane->plane_id;
2501 
2502         props = drmModeObjectGetProperties(drmmode->fd, plane_id,
2503                                            DRM_MODE_OBJECT_PLANE);
2504         if (!props) {
2505             xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
2506                     "couldn't get plane properties\n");
2507             drmModeFreePlane(kplane);
2508             continue;
2509         }
2510 
2511         drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
2512 
2513         /* Only primary planes are important for atomic page-flipping */
2514         type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
2515                                       props, DRMMODE_PLANE_TYPE__COUNT);
2516         if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
2517             drmModeFreePlane(kplane);
2518             drmModeFreeObjectProperties(props);
2519             continue;
2520         }
2521 
2522         /* Check if plane is already on this CRTC */
2523         current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
2524                                               props, 0);
2525         if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
2526             if (best_plane) {
2527                 drmModeFreePlane(best_kplane);
2528                 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
2529             }
2530             best_plane = plane_id;
2531             best_kplane = kplane;
2532             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2533                                              props, 0);
2534             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2535                                    DRMMODE_PLANE__COUNT, 1);
2536             drmModeFreeObjectProperties(props);
2537             break;
2538         }
2539 
2540         if (!best_plane) {
2541             best_plane = plane_id;
2542             best_kplane = kplane;
2543             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
2544                                              props, 0);
2545             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
2546                                    DRMMODE_PLANE__COUNT, 1);
2547         } else {
2548             drmModeFreePlane(kplane);
2549         }
2550 
2551         drmModeFreeObjectProperties(props);
2552     }
2553 
2554     drmmode_crtc->plane_id = best_plane;
2555     if (best_kplane) {
2556         drmmode_crtc->num_formats = best_kplane->count_formats;
2557         drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
2558                                        best_kplane->count_formats);
2559         if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
2560             for (i = 0; i < best_kplane->count_formats; i++)
2561                 drmmode_crtc->formats[i].format = best_kplane->formats[i];
2562         }
2563         drmModeFreePlane(best_kplane);
2564     }
2565 
2566     drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
2567     drmModeFreePlaneResources(kplane_res);
2568 }
2569 
2570 static unsigned int
drmmode_crtc_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num)2571 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
2572 {
2573     xf86CrtcPtr crtc;
2574     drmmode_crtc_private_ptr drmmode_crtc;
2575     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
2576     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
2577     modesettingPtr ms = modesettingPTR(pScrn);
2578     drmModeObjectPropertiesPtr props;
2579     static const drmmode_prop_info_rec crtc_props[] = {
2580         [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
2581         [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
2582         [DRMMODE_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT" },
2583         [DRMMODE_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE" },
2584     };
2585     int o, found = 0;
2586 
2587     /* only init possible crtcs for the outputs */
2588     for (o = 0; o < config->num_output; o++) {
2589         xf86OutputPtr output = config->output[o];
2590         drmmode_output_private_ptr drmmode_output = output->driver_private;
2591 
2592         if (drmmode_output->possible_crtcs & (1 << num)) {
2593             output->possible_crtcs |= 1 << config->num_crtc;
2594             found = 1;
2595         }
2596     }
2597 
2598     if (!found)
2599         return 0;
2600 
2601     crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
2602     if (crtc == NULL)
2603         return 0;
2604     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
2605     crtc->driver_private = drmmode_crtc;
2606     drmmode_crtc->mode_crtc =
2607         drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
2608     drmmode_crtc->drmmode = drmmode;
2609     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
2610     xorg_list_init(&drmmode_crtc->mode_list);
2611 
2612     if (drmmode->fb_flip_mode == DRMMODE_FB_FLIP_NONE)
2613         drmmode_crtc->can_flip_fb = FALSE;
2614     else
2615         drmmode_crtc->can_flip_fb = TRUE;
2616 
2617     if (1 || ms->atomic_modeset) {
2618         props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
2619                                            DRM_MODE_OBJECT_CRTC);
2620         if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
2621                                               DRMMODE_CRTC__COUNT, 0)) {
2622             xf86CrtcDestroy(crtc);
2623             return 0;
2624         }
2625 
2626         drmmode_prop_info_update(drmmode, drmmode_crtc->props,
2627                                  DRMMODE_CRTC__COUNT, props);
2628         drmModeFreeObjectProperties(props);
2629         drmmode_crtc_create_planes(crtc, num);
2630     }
2631 
2632     /* Hide any cursors which may be active from previous users */
2633     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
2634 
2635     /* Mark num'th crtc as in use on this device. */
2636     ms_ent->assigned_crtcs |= (1 << num);
2637     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
2638                    "Allocated crtc nr. %d to this screen.\n", num);
2639 
2640     drmmode_crtc->use_gamma_lut =
2641         drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id &&
2642         drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value &&
2643         xf86ReturnOptValBool(drmmode->Options, OPTION_USE_GAMMA_LUT, TRUE);
2644 
2645     return 1;
2646 }
2647 
2648 /*
2649  * Update all of the property values for an output
2650  */
2651 static void
drmmode_output_update_properties(xf86OutputPtr output)2652 drmmode_output_update_properties(xf86OutputPtr output)
2653 {
2654     drmmode_output_private_ptr drmmode_output = output->driver_private;
2655     int i, j, k;
2656     int err;
2657     drmModeConnectorPtr koutput;
2658 
2659     /* Use the most recently fetched values from the kernel */
2660     koutput = drmmode_output->mode_output;
2661 
2662     if (!koutput)
2663         return;
2664 
2665     for (i = 0; i < drmmode_output->num_props; i++) {
2666         drmmode_prop_ptr p = &drmmode_output->props[i];
2667 
2668         for (j = 0; koutput && j < koutput->count_props; j++) {
2669             if (koutput->props[j] == p->mode_prop->prop_id) {
2670 
2671                 /* Check to see if the property value has changed */
2672                 if (koutput->prop_values[j] != p->value) {
2673 
2674                     p->value = koutput->prop_values[j];
2675 
2676                     if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
2677                         INT32 value = p->value;
2678 
2679                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2680                                                      XA_INTEGER, 32, PropModeReplace, 1,
2681                                                      &value, FALSE, TRUE);
2682 
2683                         if (err != 0) {
2684                             xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2685                                        "RRChangeOutputProperty error, %d\n", err);
2686                         }
2687                     }
2688                     else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
2689                         for (k = 0; k < p->mode_prop->count_enums; k++)
2690                             if (p->mode_prop->enums[k].value == p->value)
2691                                 break;
2692                         if (k < p->mode_prop->count_enums) {
2693                             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
2694                                                          XA_ATOM, 32, PropModeReplace, 1,
2695                                                          &p->atoms[k + 1], FALSE, TRUE);
2696                             if (err != 0) {
2697                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
2698                                            "RRChangeOutputProperty error, %d\n", err);
2699                             }
2700                         }
2701                     }
2702                 }
2703                 break;
2704             }
2705         }
2706     }
2707 }
2708 
2709 static void
drmmode_output_change_status(xf86OutputPtr output,xf86OutputStatus status)2710 drmmode_output_change_status(xf86OutputPtr output, xf86OutputStatus status)
2711 {
2712     drmmode_output_private_ptr drmmode_output = output->driver_private;
2713     drmmode_ptr drmmode = drmmode_output->drmmode;
2714     drmmode_crtc_private_ptr drmmode_crtc;
2715     ScrnInfoPtr scrn = drmmode->scrn;
2716     xf86CrtcPtr crtc = output->crtc;
2717     Bool connected;
2718 
2719     if (drmmode_output->status == status)
2720         return;
2721 
2722     drmmode_output->status = status;
2723     connected = status == XF86OutputStatusConnected;
2724 
2725     xf86DrvMsg(scrn->scrnIndex, X_INFO,
2726                "Output %s status changed to %s.\n", output->name,
2727                connected ? "connected" : "disconnected");
2728 
2729     if (!crtc)
2730         return;
2731 
2732     drmmode_crtc = crtc->driver_private;
2733 
2734     if (!connected) {
2735         if (drmmode->hotplug_reset && !drmmode_crtc_connected(crtc)) {
2736             drmmode_crtc->need_modeset = TRUE;
2737 
2738             drmModeSetCrtc(drmmode->fd,
2739                            drmmode_crtc->mode_crtc->crtc_id,
2740                            0, 0, 0, NULL, 0, NULL);
2741         }
2742     } else if (drmmode_crtc->need_modeset) {
2743         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
2744                                crtc->x, crtc->y);
2745     }
2746 }
2747 
2748 static xf86OutputStatus
drmmode_output_detect(xf86OutputPtr output)2749 drmmode_output_detect(xf86OutputPtr output)
2750 {
2751     /* go to the hw and retrieve a new output struct */
2752     drmmode_output_private_ptr drmmode_output = output->driver_private;
2753     drmmode_ptr drmmode = drmmode_output->drmmode;
2754     xf86OutputStatus status;
2755 
2756     if (drmmode_output->output_id == -1)
2757         return XF86OutputStatusDisconnected;
2758 
2759     drmModeFreeConnector(drmmode_output->mode_output);
2760 
2761     drmmode_output->mode_output =
2762         drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
2763 
2764     if (!drmmode_output->mode_output) {
2765         drmmode_output->output_id = -1;
2766         return XF86OutputStatusDisconnected;
2767     }
2768 
2769     drmmode_output_update_properties(output);
2770 
2771     switch (drmmode_output->mode_output->connection) {
2772     case DRM_MODE_CONNECTED:
2773         status = XF86OutputStatusConnected;
2774         break;
2775     case DRM_MODE_DISCONNECTED:
2776         status = XF86OutputStatusDisconnected;
2777         break;
2778     default:
2779     case DRM_MODE_UNKNOWNCONNECTION:
2780         status = XF86OutputStatusUnknown;
2781         break;
2782     }
2783 
2784     drmmode_output_change_status(output, status);
2785     return status;
2786 }
2787 
2788 static Bool
drmmode_output_mode_valid(xf86OutputPtr output,DisplayModePtr pModes)2789 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
2790 {
2791     return MODE_OK;
2792 }
2793 
2794 static int
koutput_get_prop_idx(int fd,drmModeConnectorPtr koutput,int type,const char * name)2795 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
2796         int type, const char *name)
2797 {
2798     int idx = -1;
2799 
2800     for (int i = 0; i < koutput->count_props; i++) {
2801         drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
2802 
2803         if (!prop)
2804             continue;
2805 
2806         if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
2807             idx = i;
2808 
2809         drmModeFreeProperty(prop);
2810 
2811         if (idx > -1)
2812             break;
2813     }
2814 
2815     return idx;
2816 }
2817 
2818 static int
koutput_get_prop_id(int fd,drmModeConnectorPtr koutput,int type,const char * name)2819 koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
2820         int type, const char *name)
2821 {
2822     int idx = koutput_get_prop_idx(fd, koutput, type, name);
2823 
2824     return (idx > -1) ? koutput->props[idx] : -1;
2825 }
2826 
2827 static drmModePropertyBlobPtr
koutput_get_prop_blob(int fd,drmModeConnectorPtr koutput,const char * name)2828 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
2829 {
2830     drmModePropertyBlobPtr blob = NULL;
2831     int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
2832 
2833     if (idx > -1)
2834         blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
2835 
2836     return blob;
2837 }
2838 
2839 static void
drmmode_output_attach_tile(xf86OutputPtr output)2840 drmmode_output_attach_tile(xf86OutputPtr output)
2841 {
2842     drmmode_output_private_ptr drmmode_output = output->driver_private;
2843     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2844     drmmode_ptr drmmode = drmmode_output->drmmode;
2845     struct xf86CrtcTileInfo tile_info, *set = NULL;
2846 
2847     if (!koutput) {
2848         xf86OutputSetTile(output, NULL);
2849         return;
2850     }
2851 
2852     drmModeFreePropertyBlob(drmmode_output->tile_blob);
2853 
2854     /* look for a TILE property */
2855     drmmode_output->tile_blob =
2856         koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
2857 
2858     if (drmmode_output->tile_blob) {
2859         if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
2860             set = &tile_info;
2861     }
2862     xf86OutputSetTile(output, set);
2863 }
2864 
2865 static Bool
has_panel_fitter(xf86OutputPtr output)2866 has_panel_fitter(xf86OutputPtr output)
2867 {
2868     drmmode_output_private_ptr drmmode_output = output->driver_private;
2869     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2870     drmmode_ptr drmmode = drmmode_output->drmmode;
2871     int idx;
2872 
2873     /* Presume that if the output supports scaling, then we have a
2874      * panel fitter capable of adjust any mode to suit.
2875      */
2876     idx = koutput_get_prop_idx(drmmode->fd, koutput,
2877             DRM_MODE_PROP_ENUM, "scaling mode");
2878 
2879     return (idx > -1);
2880 }
2881 
2882 static DisplayModePtr
drmmode_output_add_gtf_modes(xf86OutputPtr output,DisplayModePtr Modes)2883 drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
2884 {
2885     xf86MonPtr mon = output->MonInfo;
2886     DisplayModePtr i, m, preferred = NULL;
2887     int max_x = 0, max_y = 0;
2888     float max_vrefresh = 0.0;
2889 
2890     if (mon && gtf_supported(mon))
2891         return Modes;
2892 
2893     if (!has_panel_fitter(output))
2894         return Modes;
2895 
2896     for (m = Modes; m; m = m->next) {
2897         if (m->type & M_T_PREFERRED)
2898             preferred = m;
2899         max_x = max(max_x, m->HDisplay);
2900         max_y = max(max_y, m->VDisplay);
2901         max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
2902     }
2903 
2904     max_vrefresh = max(max_vrefresh, 60.0);
2905     max_vrefresh *= (1 + SYNC_TOLERANCE);
2906 
2907     m = xf86GetDefaultModes();
2908     xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
2909 
2910     for (i = m; i; i = i->next) {
2911         if (xf86ModeVRefresh(i) > max_vrefresh)
2912             i->status = MODE_VSYNC;
2913         if (preferred &&
2914             i->HDisplay >= preferred->HDisplay &&
2915             i->VDisplay >= preferred->VDisplay &&
2916             xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
2917             i->status = MODE_VSYNC;
2918     }
2919 
2920     xf86PruneInvalidModes(output->scrn, &m, FALSE);
2921 
2922     return xf86ModesAdd(Modes, m);
2923 }
2924 
2925 static DisplayModePtr
drmmode_output_get_modes(xf86OutputPtr output)2926 drmmode_output_get_modes(xf86OutputPtr output)
2927 {
2928     drmmode_output_private_ptr drmmode_output = output->driver_private;
2929     drmModeConnectorPtr koutput = drmmode_output->mode_output;
2930     drmmode_ptr drmmode = drmmode_output->drmmode;
2931     int i;
2932     DisplayModePtr Modes = NULL, Mode;
2933     xf86MonPtr mon = NULL;
2934 
2935     if (!koutput)
2936         return NULL;
2937 
2938     drmModeFreePropertyBlob(drmmode_output->edid_blob);
2939 
2940     /* look for an EDID property */
2941     drmmode_output->edid_blob =
2942         koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
2943 
2944     if (!xf86ReturnOptValBool(drmmode->Options, OPTION_NO_EDID, FALSE) &&
2945         drmmode_output->edid_blob) {
2946         mon = xf86InterpretEDID(output->scrn->scrnIndex,
2947                                 drmmode_output->edid_blob->data);
2948         if (mon && drmmode_output->edid_blob->length > 128)
2949             mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
2950     }
2951     xf86OutputSetEDID(output, mon);
2952 
2953     drmmode_output_attach_tile(output);
2954 
2955     /* modes should already be available */
2956     for (i = 0; i < koutput->count_modes; i++) {
2957         Mode = xnfalloc(sizeof(DisplayModeRec));
2958 
2959         drmmode_ConvertFromKMode(output, &koutput->modes[i], Mode);
2960         Modes = xf86ModesAdd(Modes, Mode);
2961 
2962     }
2963 
2964     return drmmode_output_add_gtf_modes(output, Modes);
2965 }
2966 
2967 static void
drmmode_output_destroy(xf86OutputPtr output)2968 drmmode_output_destroy(xf86OutputPtr output)
2969 {
2970     drmmode_output_private_ptr drmmode_output = output->driver_private;
2971     int i;
2972 
2973     drmModeFreePropertyBlob(drmmode_output->edid_blob);
2974     drmModeFreePropertyBlob(drmmode_output->tile_blob);
2975 
2976     for (i = 0; i < drmmode_output->num_props; i++) {
2977         drmModeFreeProperty(drmmode_output->props[i].mode_prop);
2978         free(drmmode_output->props[i].atoms);
2979     }
2980     free(drmmode_output->props);
2981     if (drmmode_output->mode_output) {
2982         for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
2983             drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
2984         }
2985         drmModeFreeConnector(drmmode_output->mode_output);
2986     }
2987     free(drmmode_output->mode_encoders);
2988     free(drmmode_output);
2989     output->driver_private = NULL;
2990 }
2991 
2992 static void
drmmode_output_dpms(xf86OutputPtr output,int mode)2993 drmmode_output_dpms(xf86OutputPtr output, int mode)
2994 {
2995     modesettingPtr ms = modesettingPTR(output->scrn);
2996     drmmode_output_private_ptr drmmode_output = output->driver_private;
2997     drmmode_ptr drmmode = drmmode_output->drmmode;
2998     xf86CrtcPtr crtc = output->crtc;
2999     drmModeConnectorPtr koutput = drmmode_output->mode_output;
3000 
3001     if (!koutput)
3002         return;
3003 
3004     /* XXX Check if DPMS mode is already the right one */
3005 
3006     drmmode_output->dpms = mode;
3007 
3008     if (ms->atomic_modeset) {
3009         if (!ms->pending_modeset)
3010             drmmode_output_dpms_atomic(output, mode);
3011     } else {
3012         drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
3013                                     drmmode_output->dpms_enum_id, mode);
3014     }
3015 
3016     if (crtc) {
3017         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3018 
3019         if (mode == DPMSModeOn) {
3020             if (drmmode_crtc->need_modeset)
3021                 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
3022                                        crtc->x, crtc->y);
3023 
3024             if (drmmode_crtc->enable_flipping)
3025                 drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
3026         } else {
3027             if (drmmode_crtc->enable_flipping)
3028                 drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
3029         }
3030     }
3031 
3032     return;
3033 }
3034 
3035 static Bool
drmmode_property_ignore(drmModePropertyPtr prop)3036 drmmode_property_ignore(drmModePropertyPtr prop)
3037 {
3038     if (!prop)
3039         return TRUE;
3040     /* ignore blob prop */
3041     if (prop->flags & DRM_MODE_PROP_BLOB)
3042         return TRUE;
3043     /* ignore standard property */
3044     if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
3045         !strcmp(prop->name, "CRTC_ID"))
3046         return TRUE;
3047 
3048     return FALSE;
3049 }
3050 
3051 static void
drmmode_output_create_resources(xf86OutputPtr output)3052 drmmode_output_create_resources(xf86OutputPtr output)
3053 {
3054     drmmode_output_private_ptr drmmode_output = output->driver_private;
3055     drmModeConnectorPtr mode_output = drmmode_output->mode_output;
3056     drmmode_ptr drmmode = drmmode_output->drmmode;
3057     drmModePropertyPtr drmmode_prop;
3058     int i, j, err;
3059 
3060     /* already created */
3061     if (drmmode_output->props)
3062         return;
3063 
3064     drmmode_output->props =
3065         calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
3066     if (!drmmode_output->props)
3067         return;
3068 
3069     drmmode_output->num_props = 0;
3070     for (i = 0, j = 0; i < mode_output->count_props; i++) {
3071         drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
3072         if (drmmode_property_ignore(drmmode_prop)) {
3073             drmModeFreeProperty(drmmode_prop);
3074             continue;
3075         }
3076         drmmode_output->props[j].mode_prop = drmmode_prop;
3077         drmmode_output->props[j].value = mode_output->prop_values[i];
3078         drmmode_output->num_props++;
3079         j++;
3080     }
3081 
3082     /* Create CONNECTOR_ID property */
3083     {
3084         Atom    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
3085         INT32   value = mode_output->connector_id;
3086 
3087         if (name != BAD_RESOURCE) {
3088             err = RRConfigureOutputProperty(output->randr_output, name,
3089                                             FALSE, FALSE, TRUE,
3090                                             1, &value);
3091             if (err != 0) {
3092                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3093                            "RRConfigureOutputProperty error, %d\n", err);
3094             }
3095             err = RRChangeOutputProperty(output->randr_output, name,
3096                                          XA_INTEGER, 32, PropModeReplace, 1,
3097                                          &value, FALSE, FALSE);
3098             if (err != 0) {
3099                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3100                            "RRChangeOutputProperty error, %d\n", err);
3101             }
3102         }
3103     }
3104 
3105     for (i = 0; i < drmmode_output->num_props; i++) {
3106         drmmode_prop_ptr p = &drmmode_output->props[i];
3107 
3108         drmmode_prop = p->mode_prop;
3109 
3110         if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
3111             INT32 prop_range[2];
3112             INT32 value = p->value;
3113 
3114             p->num_atoms = 1;
3115             p->atoms = calloc(p->num_atoms, sizeof(Atom));
3116             if (!p->atoms)
3117                 continue;
3118             p->atoms[0] =
3119                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
3120             prop_range[0] = drmmode_prop->values[0];
3121             prop_range[1] = drmmode_prop->values[1];
3122             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
3123                                             FALSE, TRUE,
3124                                             drmmode_prop->
3125                                             flags & DRM_MODE_PROP_IMMUTABLE ?
3126                                             TRUE : FALSE, 2, prop_range);
3127             if (err != 0) {
3128                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3129                            "RRConfigureOutputProperty error, %d\n", err);
3130             }
3131             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
3132                                          XA_INTEGER, 32, PropModeReplace, 1,
3133                                          &value, FALSE, TRUE);
3134             if (err != 0) {
3135                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3136                            "RRChangeOutputProperty error, %d\n", err);
3137             }
3138         }
3139         else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
3140             p->num_atoms = drmmode_prop->count_enums + 1;
3141             p->atoms = calloc(p->num_atoms, sizeof(Atom));
3142             if (!p->atoms)
3143                 continue;
3144             p->atoms[0] =
3145                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
3146             for (j = 1; j <= drmmode_prop->count_enums; j++) {
3147                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
3148 
3149                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
3150             }
3151             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
3152                                             FALSE, FALSE,
3153                                             drmmode_prop->
3154                                             flags & DRM_MODE_PROP_IMMUTABLE ?
3155                                             TRUE : FALSE, p->num_atoms - 1,
3156                                             (INT32 *) &p->atoms[1]);
3157             if (err != 0) {
3158                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3159                            "RRConfigureOutputProperty error, %d\n", err);
3160             }
3161             for (j = 0; j < drmmode_prop->count_enums; j++)
3162                 if (drmmode_prop->enums[j].value == p->value)
3163                     break;
3164             /* there's always a matching value */
3165             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
3166                                          XA_ATOM, 32, PropModeReplace, 1,
3167                                          &p->atoms[j + 1], FALSE, TRUE);
3168             if (err != 0) {
3169                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
3170                            "RRChangeOutputProperty error, %d\n", err);
3171             }
3172         }
3173     }
3174 }
3175 
3176 static Bool
drmmode_output_set_property(xf86OutputPtr output,Atom property,RRPropertyValuePtr value)3177 drmmode_output_set_property(xf86OutputPtr output, Atom property,
3178                             RRPropertyValuePtr value)
3179 {
3180     drmmode_output_private_ptr drmmode_output = output->driver_private;
3181     drmmode_ptr drmmode = drmmode_output->drmmode;
3182     int i;
3183 
3184     for (i = 0; i < drmmode_output->num_props; i++) {
3185         drmmode_prop_ptr p = &drmmode_output->props[i];
3186 
3187         if (p->atoms[0] != property)
3188             continue;
3189 
3190         if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
3191             uint32_t val;
3192 
3193             if (value->type != XA_INTEGER || value->format != 32 ||
3194                 value->size != 1)
3195                 return FALSE;
3196             val = *(uint32_t *) value->data;
3197 
3198             drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
3199                                         p->mode_prop->prop_id, (uint64_t) val);
3200             return TRUE;
3201         }
3202         else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
3203             Atom atom;
3204             const char *name;
3205             int j;
3206 
3207             if (value->type != XA_ATOM || value->format != 32 ||
3208                 value->size != 1)
3209                 return FALSE;
3210             memcpy(&atom, value->data, 4);
3211             if (!(name = NameForAtom(atom)))
3212                 return FALSE;
3213 
3214             /* search for matching name string, then set its value down */
3215             for (j = 0; j < p->mode_prop->count_enums; j++) {
3216                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
3217                     drmModeConnectorSetProperty(drmmode->fd,
3218                                                 drmmode_output->output_id,
3219                                                 p->mode_prop->prop_id,
3220                                                 p->mode_prop->enums[j].value);
3221                     return TRUE;
3222                 }
3223             }
3224         }
3225     }
3226 
3227     return TRUE;
3228 }
3229 
3230 static Bool
drmmode_output_get_property(xf86OutputPtr output,Atom property)3231 drmmode_output_get_property(xf86OutputPtr output, Atom property)
3232 {
3233     return TRUE;
3234 }
3235 
3236 static const xf86OutputFuncsRec drmmode_output_funcs = {
3237     .dpms = drmmode_output_dpms,
3238     .create_resources = drmmode_output_create_resources,
3239     .set_property = drmmode_output_set_property,
3240     .get_property = drmmode_output_get_property,
3241     .detect = drmmode_output_detect,
3242     .mode_valid = drmmode_output_mode_valid,
3243 
3244     .get_modes = drmmode_output_get_modes,
3245     .destroy = drmmode_output_destroy
3246 };
3247 
3248 static int subpixel_conv_table[7] = {
3249     0,
3250     SubPixelUnknown,
3251     SubPixelHorizontalRGB,
3252     SubPixelHorizontalBGR,
3253     SubPixelVerticalRGB,
3254     SubPixelVerticalBGR,
3255     SubPixelNone
3256 };
3257 
3258 static const char *const output_names[] = {
3259     "None",
3260     "VGA",
3261     "DVI-I",
3262     "DVI-D",
3263     "DVI-A",
3264     "Composite",
3265     "SVIDEO",
3266     "LVDS",
3267     "Component",
3268     "DIN",
3269     "DP",
3270     "HDMI",
3271     "HDMI-B",
3272     "TV",
3273     "eDP",
3274     "Virtual",
3275     "DSI",
3276     "DPI",
3277 };
3278 
find_output(ScrnInfoPtr pScrn,int id)3279 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
3280 {
3281     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3282     int i;
3283     for (i = 0; i < xf86_config->num_output; i++) {
3284         xf86OutputPtr output = xf86_config->output[i];
3285         drmmode_output_private_ptr drmmode_output;
3286 
3287         drmmode_output = output->driver_private;
3288         if (drmmode_output->output_id == id)
3289             return output;
3290     }
3291     return NULL;
3292 }
3293 
parse_path_blob(drmModePropertyBlobPtr path_blob,int * conn_base_id,char ** path)3294 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
3295 {
3296     char *conn;
3297     char conn_id[5];
3298     int id, len;
3299     char *blob_data;
3300 
3301     if (!path_blob)
3302         return -1;
3303 
3304     blob_data = path_blob->data;
3305     /* we only handle MST paths for now */
3306     if (strncmp(blob_data, "mst:", 4))
3307         return -1;
3308 
3309     conn = strchr(blob_data + 4, '-');
3310     if (!conn)
3311         return -1;
3312     len = conn - (blob_data + 4);
3313     if (len + 1> 5)
3314         return -1;
3315     memcpy(conn_id, blob_data + 4, len);
3316     conn_id[len] = '\0';
3317     id = strtoul(conn_id, NULL, 10);
3318 
3319     *conn_base_id = id;
3320 
3321     *path = conn + 1;
3322     return 0;
3323 }
3324 
3325 static void
drmmode_create_name(ScrnInfoPtr pScrn,drmModeConnectorPtr koutput,char * name,drmModePropertyBlobPtr path_blob)3326 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
3327 		    drmModePropertyBlobPtr path_blob)
3328 {
3329     int ret;
3330     char *extra_path;
3331     int conn_id;
3332     xf86OutputPtr output;
3333 
3334     ret = parse_path_blob(path_blob, &conn_id, &extra_path);
3335     if (ret == -1)
3336         goto fallback;
3337 
3338     output = find_output(pScrn, conn_id);
3339     if (!output)
3340         goto fallback;
3341 
3342     snprintf(name, 32, "%s-%s", output->name, extra_path);
3343     return;
3344 
3345  fallback:
3346     if (koutput->connector_type >= ARRAY_SIZE(output_names))
3347         snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
3348     else if (pScrn->is_gpu)
3349         snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
3350     else
3351         snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
3352 }
3353 
3354 static unsigned int
drmmode_output_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,drmModeResPtr mode_res,int num,Bool dynamic,int crtcshift)3355 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
3356 {
3357     xf86OutputPtr output;
3358     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
3359     modesettingPtr ms = modesettingPTR(pScrn);
3360     drmModeConnectorPtr koutput;
3361     drmModeEncoderPtr *kencoders = NULL;
3362     drmmode_output_private_ptr drmmode_output;
3363     char name[32];
3364     int i;
3365     Bool nonDesktop = FALSE;
3366     drmModePropertyBlobPtr path_blob = NULL;
3367     const char *s;
3368     drmModeObjectPropertiesPtr props;
3369     static const drmmode_prop_info_rec connector_props[] = {
3370         [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
3371     };
3372 
3373     drmmode_prop_info_ptr crtc_info;
3374     unsigned int current_crtc;
3375 
3376     koutput =
3377         drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
3378     if (!koutput)
3379         return 0;
3380 
3381     path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
3382     i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
3383     if (i >= 0)
3384         nonDesktop = koutput->prop_values[i] != 0;
3385 
3386     drmmode_create_name(pScrn, koutput, name, path_blob);
3387 
3388     if (path_blob)
3389         drmModeFreePropertyBlob(path_blob);
3390 
3391     if (path_blob && dynamic) {
3392         /* see if we have an output with this name already
3393            and hook stuff up */
3394         for (i = 0; i < xf86_config->num_output; i++) {
3395             output = xf86_config->output[i];
3396 
3397             if (strncmp(output->name, name, 32))
3398                 continue;
3399 
3400             drmmode_output = output->driver_private;
3401             drmmode_output->output_id = mode_res->connectors[num];
3402             drmmode_output->mode_output = koutput;
3403             output->non_desktop = nonDesktop;
3404             return 1;
3405         }
3406     }
3407 
3408     kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
3409     if (!kencoders) {
3410         goto out_free_encoders;
3411     }
3412 
3413     for (i = 0; i < koutput->count_encoders; i++) {
3414         kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
3415         if (!kencoders[i]) {
3416             goto out_free_encoders;
3417         }
3418     }
3419 
3420     if (xf86IsEntityShared(pScrn->entityList[0])) {
3421         if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
3422             if (!drmmode_zaphod_string_matches(pScrn, s, name))
3423                 goto out_free_encoders;
3424         } else {
3425             if (!drmmode->is_secondary && (num != 0))
3426                 goto out_free_encoders;
3427             else if (drmmode->is_secondary && (num != 1))
3428                 goto out_free_encoders;
3429         }
3430     }
3431 
3432     output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
3433     if (!output) {
3434         goto out_free_encoders;
3435     }
3436 
3437     drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
3438     if (!drmmode_output) {
3439         xf86OutputDestroy(output);
3440         goto out_free_encoders;
3441     }
3442 
3443     s = xf86GetOptValString(drmmode->Options, OPTION_VIRTUAL_SIZE);
3444     if (s)
3445         s = strstr(s, output->name);
3446     if (s) {
3447         int w, h;
3448         if (sscanf(s + strlen(output->name) + 1, "%dx%d", &w, &h) == 2 &&
3449             w > 0 && h > 0) {
3450             drmmode_output->virtual_width = w;
3451             drmmode_output->virtual_height = h;
3452             xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3453                        "Using virtual size %dx%d for connector: %s\n",
3454                        drmmode_output->virtual_width,
3455                        drmmode_output->virtual_height, output->name);
3456         }
3457     }
3458 
3459     s = xf86GetOptValString(drmmode->Options, OPTION_PADDING);
3460     if (s)
3461         s = strstr(s, output->name);
3462     if (s) {
3463         int top, bottom, left, right;
3464         if (sscanf(s + strlen(output->name) + 1, "%d,%d,%d,%d",
3465                    &top, &bottom, &left, &right) == 4) {
3466             if (top >= 0 && bottom >= 0 && left >= 0 && right >= 0) {
3467                 drmmode_output->padding_top = top;
3468                 drmmode_output->padding_bottom = bottom;
3469                 drmmode_output->padding_left = left;
3470                 drmmode_output->padding_right = right;
3471                 xf86DrvMsg(pScrn->scrnIndex, X_INFO,
3472                            "Using padding top:%d bottom:%d left:%d right:%d\n",
3473                            drmmode_output->padding_top,
3474                            drmmode_output->padding_bottom,
3475                            drmmode_output->padding_left,
3476                            drmmode_output->padding_right);
3477             }
3478         }
3479     }
3480 
3481     drmmode_output->output_id = mode_res->connectors[num];
3482     drmmode_output->mode_output = koutput;
3483     drmmode_output->mode_encoders = kencoders;
3484     drmmode_output->drmmode = drmmode;
3485     output->mm_width = koutput->mmWidth;
3486     output->mm_height = koutput->mmHeight;
3487 
3488     output->subpixel_order = subpixel_conv_table[koutput->subpixel];
3489     output->interlaceAllowed = TRUE;
3490     output->doubleScanAllowed = TRUE;
3491     output->driver_private = drmmode_output;
3492     output->non_desktop = nonDesktop;
3493 
3494     drmmode_output->possible_crtcs = 0x7f;
3495     for (i = 0; i < koutput->count_encoders; i++) {
3496         drmmode_output->possible_crtcs &= kencoders[i]->possible_crtcs;
3497     }
3498 
3499     if (!dynamic) {
3500         /* would be updated in crtc init */
3501         output->possible_crtcs = 0;
3502     } else {
3503         output->possible_crtcs = drmmode_output->possible_crtcs;
3504     }
3505 
3506     /* work out the possible clones later */
3507     output->possible_clones = 0;
3508 
3509     if (!drmmode_prop_info_copy(drmmode_output->props_connector,
3510                                 connector_props, DRMMODE_CONNECTOR__COUNT,
3511                                 0)) {
3512         goto out_free_encoders;
3513     }
3514     props = drmModeObjectGetProperties(drmmode->fd,
3515                                        drmmode_output->output_id,
3516                                        DRM_MODE_OBJECT_CONNECTOR);
3517     drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
3518                              DRMMODE_CONNECTOR__COUNT, props);
3519     crtc_info = &drmmode_output->props_connector[DRMMODE_CONNECTOR_CRTC_ID];
3520     current_crtc = drmmode_prop_get_value(crtc_info, props,
3521                                           DRMMODE_PLANE_TYPE__COUNT);
3522     drmModeFreeObjectProperties(props);
3523 
3524     if (xf86ReturnOptValBool(drmmode->Options, OPTION_BIND_CURRENT, TRUE)) {
3525         for (i = 0; i < mode_res->count_crtcs; i++) {
3526             if (current_crtc == mode_res->crtcs[i]) {
3527                 xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, 0,
3528                                "Bind output %d to current crtc %d.\n",
3529                                drmmode_output->output_id, current_crtc);
3530                 drmmode_output->possible_crtcs = 1 << i;
3531                 break;
3532             }
3533         }
3534     }
3535 
3536     if (!ms->atomic_modeset) {
3537         drmmode_output->dpms_enum_id =
3538             koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
3539                                 "DPMS");
3540     }
3541 
3542     if (dynamic)
3543         output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
3544     return 1;
3545 
3546  out_free_encoders:
3547     if (kencoders) {
3548         for (i = 0; i < koutput->count_encoders; i++)
3549             drmModeFreeEncoder(kencoders[i]);
3550         free(kencoders);
3551     }
3552     drmModeFreeConnector(koutput);
3553 
3554     return 0;
3555 }
3556 
3557 static uint32_t
find_clones(ScrnInfoPtr scrn,xf86OutputPtr output)3558 find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
3559 {
3560     drmmode_output_private_ptr drmmode_output =
3561         output->driver_private, clone_drmout;
3562     int i;
3563     xf86OutputPtr clone_output;
3564     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3565     int index_mask = 0;
3566 
3567     if (drmmode_output->enc_clone_mask == 0)
3568         return index_mask;
3569 
3570     for (i = 0; i < xf86_config->num_output; i++) {
3571         clone_output = xf86_config->output[i];
3572         clone_drmout = clone_output->driver_private;
3573         if (output == clone_output)
3574             continue;
3575 
3576         if (clone_drmout->enc_mask == 0)
3577             continue;
3578         if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
3579             index_mask |= (1 << i);
3580     }
3581     return index_mask;
3582 }
3583 
3584 static void
drmmode_clones_init(ScrnInfoPtr scrn,drmmode_ptr drmmode,drmModeResPtr mode_res)3585 drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
3586 {
3587     int i, j;
3588     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3589 
3590     for (i = 0; i < xf86_config->num_output; i++) {
3591         xf86OutputPtr output = xf86_config->output[i];
3592         drmmode_output_private_ptr drmmode_output;
3593 
3594         drmmode_output = output->driver_private;
3595         drmmode_output->enc_clone_mask = 0xff;
3596         /* and all the possible encoder clones for this output together */
3597         for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
3598             int k;
3599 
3600             for (k = 0; k < mode_res->count_encoders; k++) {
3601                 if (mode_res->encoders[k] ==
3602                     drmmode_output->mode_encoders[j]->encoder_id)
3603                     drmmode_output->enc_mask |= (1 << k);
3604             }
3605 
3606             drmmode_output->enc_clone_mask &=
3607                 drmmode_output->mode_encoders[j]->possible_clones;
3608         }
3609     }
3610 
3611     for (i = 0; i < xf86_config->num_output; i++) {
3612         xf86OutputPtr output = xf86_config->output[i];
3613 
3614         output->possible_clones = find_clones(scrn, output);
3615     }
3616 }
3617 
3618 static Bool
drmmode_set_pixmap_bo(drmmode_ptr drmmode,PixmapPtr pixmap,drmmode_bo * bo)3619 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
3620 {
3621     ScrnInfoPtr scrn = drmmode->scrn;
3622 
3623     if (drmmode->exa)
3624         return ms_exa_set_pixmap_bo(scrn, pixmap, bo->dumb, FALSE);
3625 
3626 #ifdef GLAMOR_HAS_GBM
3627     if (!drmmode->glamor)
3628         return TRUE;
3629 
3630     if (!glamor_egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
3631                                                        bo->used_modifiers)) {
3632         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
3633         return FALSE;
3634     }
3635     bo->owned_gbm = FALSE;
3636 #endif
3637 
3638     return TRUE;
3639 }
3640 
3641 Bool
drmmode_handle_new_screen_pixmap(drmmode_ptr drmmode)3642 drmmode_handle_new_screen_pixmap(drmmode_ptr drmmode)
3643 {
3644     ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
3645     PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
3646 
3647     if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
3648         return FALSE;
3649 
3650     return TRUE;
3651 }
3652 
3653 static Bool
drmmode_xf86crtc_resize(ScrnInfoPtr scrn,int width,int height)3654 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
3655 {
3656     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
3657     modesettingPtr ms = modesettingPTR(scrn);
3658     drmmode_ptr drmmode = &ms->drmmode;
3659     drmmode_bo old_front;
3660     ScreenPtr screen = xf86ScrnToScreen(scrn);
3661     uint32_t old_fb_id;
3662     int i, pitch, old_width, old_height, old_pitch;
3663     int cpp = (scrn->bitsPerPixel + 7) / 8;
3664     int kcpp = (drmmode->kbpp + 7) / 8;
3665     PixmapPtr ppix = screen->GetScreenPixmap(screen);
3666     void *new_pixels = NULL;
3667 
3668     if (scrn->virtualX == width && scrn->virtualY == height)
3669         return TRUE;
3670 
3671     xf86DrvMsg(scrn->scrnIndex, X_INFO,
3672                "Allocate new frame buffer %dx%d stride\n", width, height);
3673 
3674     old_width = scrn->virtualX;
3675     old_height = scrn->virtualY;
3676     old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3677     old_front = drmmode->front_bo;
3678     old_fb_id = drmmode->fb_id;
3679     drmmode->fb_id = 0;
3680 
3681     if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
3682                            width, height, drmmode->kbpp))
3683         goto fail;
3684 
3685     pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
3686 
3687     scrn->virtualX = width;
3688     scrn->virtualY = height;
3689     scrn->displayWidth = pitch / kcpp;
3690 
3691     if (!drmmode->gbm && !drmmode->exa) {
3692         new_pixels = drmmode_map_front_bo(drmmode);
3693         if (!new_pixels)
3694             goto fail;
3695     }
3696 
3697     if (drmmode->shadow_enable) {
3698         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3699         new_pixels = calloc(1, size);
3700         if (new_pixels == NULL)
3701             goto fail;
3702         free(drmmode->shadow_fb);
3703         drmmode->shadow_fb = new_pixels;
3704     }
3705 
3706     if (drmmode->shadow_enable2) {
3707         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
3708         void *fb2 = calloc(1, size);
3709         free(drmmode->shadow_fb2);
3710         drmmode->shadow_fb2 = fb2;
3711     }
3712 
3713     screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
3714                                scrn->displayWidth * cpp, new_pixels);
3715 
3716     if (!drmmode_handle_new_screen_pixmap(drmmode))
3717         goto fail;
3718 
3719     drmmode_clear_pixmap(ppix);
3720 
3721     for (i = 0; i < xf86_config->num_crtc; i++) {
3722         xf86CrtcPtr crtc = xf86_config->crtc[i];
3723 
3724         if (!crtc->enabled)
3725             continue;
3726 
3727         drmmode_set_mode_major(crtc, &crtc->mode,
3728                                crtc->rotation, crtc->x, crtc->y);
3729     }
3730 
3731     if (old_fb_id)
3732         drmModeRmFB(drmmode->fd, old_fb_id);
3733 
3734     drmmode_bo_destroy(drmmode, &old_front);
3735 
3736     return TRUE;
3737 
3738  fail:
3739     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
3740     drmmode->front_bo = old_front;
3741     scrn->virtualX = old_width;
3742     scrn->virtualY = old_height;
3743     scrn->displayWidth = old_pitch / kcpp;
3744     drmmode->fb_id = old_fb_id;
3745 
3746     return FALSE;
3747 }
3748 
3749 static void
drmmode_validate_leases(ScrnInfoPtr scrn)3750 drmmode_validate_leases(ScrnInfoPtr scrn)
3751 {
3752     ScreenPtr screen = scrn->pScreen;
3753     rrScrPrivPtr scr_priv;
3754     modesettingPtr ms = modesettingPTR(scrn);
3755     drmmode_ptr drmmode = &ms->drmmode;
3756     drmModeLesseeListPtr lessees;
3757     RRLeasePtr lease, next;
3758     int l;
3759 
3760     /* Bail out if RandR wasn't initialized. */
3761     if (!dixPrivateKeyRegistered(rrPrivKey))
3762         return;
3763 
3764     scr_priv = rrGetScrPriv(screen);
3765 
3766     /* We can't talk to the kernel about leases when VT switched */
3767     if (!scrn->vtSema)
3768         return;
3769 
3770     lessees = drmModeListLessees(drmmode->fd);
3771     if (!lessees)
3772         return;
3773 
3774     xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
3775         drmmode_lease_private_ptr lease_private = lease->devPrivate;
3776 
3777         for (l = 0; l < lessees->count; l++) {
3778             if (lessees->lessees[l] == lease_private->lessee_id)
3779                 break;
3780         }
3781 
3782         /* check to see if the lease has gone away */
3783         if (l == lessees->count) {
3784             free(lease_private);
3785             lease->devPrivate = NULL;
3786             xf86CrtcLeaseTerminated(lease);
3787         }
3788     }
3789 
3790     free(lessees);
3791 }
3792 
3793 static int
drmmode_create_lease(RRLeasePtr lease,int * fd)3794 drmmode_create_lease(RRLeasePtr lease, int *fd)
3795 {
3796     ScreenPtr screen = lease->screen;
3797     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3798     modesettingPtr ms = modesettingPTR(scrn);
3799     drmmode_ptr drmmode = &ms->drmmode;
3800     int ncrtc = lease->numCrtcs;
3801     int noutput = lease->numOutputs;
3802     int nobjects;
3803     int c, o;
3804     int i;
3805     int lease_fd;
3806     uint32_t *objects;
3807     drmmode_lease_private_ptr   lease_private;
3808 
3809     nobjects = ncrtc + noutput;
3810 
3811     if (ms->atomic_modeset)
3812         nobjects += ncrtc; /* account for planes as well */
3813 
3814     if (nobjects == 0)
3815         return BadValue;
3816 
3817     lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
3818     if (!lease_private)
3819         return BadAlloc;
3820 
3821     objects = xallocarray(nobjects, sizeof (uint32_t));
3822 
3823     if (!objects) {
3824         free(lease_private);
3825         return BadAlloc;
3826     }
3827 
3828     i = 0;
3829 
3830     /* Add CRTC and plane ids */
3831     for (c = 0; c < ncrtc; c++) {
3832         xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
3833         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3834 
3835         objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
3836         if (ms->atomic_modeset)
3837             objects[i++] = drmmode_crtc->plane_id;
3838     }
3839 
3840     /* Add connector ids */
3841 
3842     for (o = 0; o < noutput; o++) {
3843         xf86OutputPtr   output = lease->outputs[o]->devPrivate;
3844         drmmode_output_private_ptr drmmode_output = output->driver_private;
3845 
3846         objects[i++] = drmmode_output->mode_output->connector_id;
3847     }
3848 
3849     /* call kernel to create lease */
3850     assert (i == nobjects);
3851 
3852     lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
3853 
3854     free(objects);
3855 
3856     if (lease_fd < 0) {
3857         free(lease_private);
3858         return BadMatch;
3859     }
3860 
3861     lease->devPrivate = lease_private;
3862 
3863     xf86CrtcLeaseStarted(lease);
3864 
3865     *fd = lease_fd;
3866     return Success;
3867 }
3868 
3869 static void
drmmode_terminate_lease(RRLeasePtr lease)3870 drmmode_terminate_lease(RRLeasePtr lease)
3871 {
3872     ScreenPtr screen = lease->screen;
3873     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
3874     modesettingPtr ms = modesettingPTR(scrn);
3875     drmmode_ptr drmmode = &ms->drmmode;
3876     drmmode_lease_private_ptr lease_private = lease->devPrivate;
3877 
3878     if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
3879         free(lease_private);
3880         lease->devPrivate = NULL;
3881         xf86CrtcLeaseTerminated(lease);
3882     }
3883 }
3884 
3885 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
3886     .resize = drmmode_xf86crtc_resize,
3887     .create_lease = drmmode_create_lease,
3888     .terminate_lease = drmmode_terminate_lease
3889 };
3890 
3891 Bool
drmmode_pre_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int cpp)3892 drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
3893 {
3894     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
3895     int i;
3896     int ret;
3897     uint64_t value = 0;
3898     unsigned int crtcs_needed = 0;
3899     drmModeResPtr mode_res;
3900     int crtcshift;
3901 
3902     /* check for dumb capability */
3903     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
3904     if (ret > 0 || value != 1) {
3905         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
3906                    "KMS doesn't support dumb interface\n");
3907         return FALSE;
3908     }
3909 
3910     xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
3911 
3912     drmmode->scrn = pScrn;
3913     drmmode->cpp = cpp;
3914     mode_res = drmModeGetResources(drmmode->fd);
3915     if (!mode_res)
3916         return FALSE;
3917 
3918     crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
3919     for (i = 0; i < mode_res->count_connectors; i++)
3920         crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
3921                                             crtcshift);
3922 
3923     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
3924                    "Up to %d crtcs needed for screen.\n", crtcs_needed);
3925 
3926     xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
3927                          mode_res->max_height);
3928     for (i = 0; i < mode_res->count_crtcs; i++)
3929         if (!xf86IsEntityShared(pScrn->entityList[0]) ||
3930             (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
3931             crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
3932 
3933     /* All ZaphodHeads outputs provided with matching crtcs? */
3934     if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
3935         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
3936                    "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
3937                    crtcs_needed);
3938 
3939     /* workout clones */
3940     drmmode_clones_init(pScrn, drmmode, mode_res);
3941 
3942     drmModeFreeResources(mode_res);
3943     xf86ProviderSetup(pScrn, NULL, "modesetting");
3944 
3945     xf86InitialConfiguration(pScrn, TRUE);
3946 
3947     return TRUE;
3948 }
3949 
3950 Bool
drmmode_init(ScrnInfoPtr pScrn,drmmode_ptr drmmode)3951 drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
3952 {
3953 #ifdef GLAMOR_HAS_GBM
3954     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
3955 
3956     if (drmmode->glamor) {
3957         if (!glamor_init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
3958             return FALSE;
3959         }
3960 #ifdef GBM_BO_WITH_MODIFIERS
3961         glamor_set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
3962 #endif
3963     }
3964 #endif
3965 
3966     return TRUE;
3967 }
3968 
3969 void
drmmode_adjust_frame(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int x,int y)3970 drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
3971 {
3972     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3973     xf86OutputPtr output = config->output[config->compat_output];
3974     xf86CrtcPtr crtc = output->crtc;
3975 
3976     if (crtc && crtc->enabled) {
3977         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
3978     }
3979 }
3980 
3981 Bool
drmmode_set_desired_modes(ScrnInfoPtr pScrn,drmmode_ptr drmmode,Bool set_hw,Bool ign_err)3982 drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
3983                           Bool ign_err)
3984 {
3985     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
3986     Bool success = TRUE;
3987     int c;
3988 
3989     for (c = 0; c < config->num_crtc; c++) {
3990         xf86CrtcPtr crtc = config->crtc[c];
3991         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
3992         xf86OutputPtr output = NULL;
3993         int o;
3994 
3995         /* Skip disabled CRTCs */
3996         if (!crtc->enabled) {
3997             if (set_hw) {
3998                 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
3999                                0, 0, 0, NULL, 0, NULL);
4000             }
4001             continue;
4002         }
4003 
4004         if (config->output[config->compat_output]->crtc == crtc)
4005             output = config->output[config->compat_output];
4006         else {
4007             for (o = 0; o < config->num_output; o++)
4008                 if (config->output[o]->crtc == crtc) {
4009                     output = config->output[o];
4010                     break;
4011                 }
4012         }
4013         /* paranoia */
4014         if (!output)
4015             continue;
4016 
4017         /* Mark that we'll need to re-set the mode for sure */
4018         memset(&crtc->mode, 0, sizeof(crtc->mode));
4019         if (!crtc->desiredMode.CrtcHDisplay) {
4020             DisplayModePtr mode =
4021                 xf86OutputFindClosestMode(output, pScrn->currentMode);
4022 
4023             if (!mode)
4024                 return FALSE;
4025             crtc->desiredMode = *mode;
4026             crtc->desiredRotation = RR_Rotate_0;
4027             crtc->desiredX = 0;
4028             crtc->desiredY = 0;
4029         }
4030 
4031         if (set_hw) {
4032             if (!crtc->funcs->
4033                 set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
4034                                crtc->desiredX, crtc->desiredY)) {
4035                 if (!ign_err)
4036                     return FALSE;
4037                 else {
4038                     success = FALSE;
4039                     crtc->enabled = FALSE;
4040                     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
4041                                "Failed to set the desired mode on connector %s\n",
4042                                output->name);
4043                 }
4044             }
4045         } else {
4046             crtc->mode = crtc->desiredMode;
4047             crtc->rotation = crtc->desiredRotation;
4048             crtc->x = crtc->desiredX;
4049             crtc->y = crtc->desiredY;
4050             if (!drmmode_apply_transform(crtc))
4051                 return FALSE;
4052         }
4053     }
4054 
4055     /* Validate leases on VT re-entry */
4056     drmmode_validate_leases(pScrn);
4057 
4058     return success;
4059 }
4060 
4061 static void
drmmode_load_palette(ScrnInfoPtr pScrn,int numColors,int * indices,LOCO * colors,VisualPtr pVisual)4062 drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
4063                      int *indices, LOCO * colors, VisualPtr pVisual)
4064 {
4065     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4066     uint16_t lut_r[256], lut_g[256], lut_b[256];
4067     int index, j, i;
4068     int c;
4069 
4070     for (c = 0; c < xf86_config->num_crtc; c++) {
4071         xf86CrtcPtr crtc = xf86_config->crtc[c];
4072         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4073 
4074         for (i = 0; i < 256; i++) {
4075             lut_r[i] = drmmode_crtc->lut_r[i] << 6;
4076             lut_g[i] = drmmode_crtc->lut_g[i] << 6;
4077             lut_b[i] = drmmode_crtc->lut_b[i] << 6;
4078         }
4079 
4080         switch (pScrn->depth) {
4081         case 15:
4082             for (i = 0; i < numColors; i++) {
4083                 index = indices[i];
4084                 for (j = 0; j < 8; j++) {
4085                     lut_r[index * 8 + j] = colors[index].red << 6;
4086                     lut_g[index * 8 + j] = colors[index].green << 6;
4087                     lut_b[index * 8 + j] = colors[index].blue << 6;
4088                 }
4089             }
4090             break;
4091         case 16:
4092             for (i = 0; i < numColors; i++) {
4093                 index = indices[i];
4094 
4095                 if (i <= 31) {
4096                     for (j = 0; j < 8; j++) {
4097                         lut_r[index * 8 + j] = colors[index].red << 6;
4098                         lut_b[index * 8 + j] = colors[index].blue << 6;
4099                     }
4100                 }
4101 
4102                 for (j = 0; j < 4; j++) {
4103                     lut_g[index * 4 + j] = colors[index].green << 6;
4104                 }
4105             }
4106             break;
4107         default:
4108             for (i = 0; i < numColors; i++) {
4109                 index = indices[i];
4110                 lut_r[index] = colors[index].red << 6;
4111                 lut_g[index] = colors[index].green << 6;
4112                 lut_b[index] = colors[index].blue << 6;
4113             }
4114             break;
4115         }
4116 
4117         /* Make the change through RandR */
4118         if (crtc->randr_crtc)
4119             RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
4120         else
4121             crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
4122     }
4123 }
4124 
4125 static Bool
drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc,int num)4126 drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc, int num)
4127 {
4128     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4129     uint64_t size;
4130 
4131     if (!drmmode_crtc->use_gamma_lut)
4132         return TRUE;
4133 
4134     assert(drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id);
4135 
4136     size = drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value;
4137 
4138     if (size != crtc->gamma_size) {
4139         ScrnInfoPtr pScrn = crtc->scrn;
4140         uint16_t *gamma = malloc(3 * size * sizeof(uint16_t));
4141 
4142         if (gamma) {
4143             free(crtc->gamma_red);
4144 
4145             crtc->gamma_size = size;
4146             crtc->gamma_red = gamma;
4147             crtc->gamma_green = gamma + size;
4148             crtc->gamma_blue = gamma + size * 2;
4149 
4150             xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
4151                            "Gamma ramp set to %ld entries on CRTC %d\n",
4152                            size, num);
4153         } else {
4154             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
4155                        "Failed to allocate memory for %ld gamma ramp entries "
4156                        "on CRTC %d.\n",
4157                        size, num);
4158             return FALSE;
4159         }
4160     }
4161 
4162     return TRUE;
4163 }
4164 
4165 Bool
drmmode_setup_colormap(ScreenPtr pScreen,ScrnInfoPtr pScrn)4166 drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
4167 {
4168     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4169     int i;
4170 
4171     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
4172               "Initializing kms color map for depth %d, %d bpc.\n",
4173               pScrn->depth, pScrn->rgbBits);
4174     if (!miCreateDefColormap(pScreen))
4175         return FALSE;
4176 
4177     /* If the GAMMA_LUT property is available, replace the server's default
4178      * gamma ramps with ones of the appropriate size. */
4179     for (i = 0; i < xf86_config->num_crtc; i++)
4180         if (!drmmode_crtc_upgrade_lut(xf86_config->crtc[i], i))
4181             return FALSE;
4182 
4183     /* Adapt color map size and depth to color depth of screen. */
4184     if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
4185                              drmmode_load_palette, NULL,
4186                              CMAP_PALETTED_TRUECOLOR |
4187                              CMAP_RELOAD_ON_MODE_SWITCH))
4188         return FALSE;
4189     return TRUE;
4190 }
4191 
4192 #define DRM_MODE_LINK_STATUS_GOOD       0
4193 #define DRM_MODE_LINK_STATUS_BAD        1
4194 
4195 void
drmmode_update_kms_state(drmmode_ptr drmmode)4196 drmmode_update_kms_state(drmmode_ptr drmmode)
4197 {
4198     ScrnInfoPtr scrn = drmmode->scrn;
4199     drmModeResPtr mode_res;
4200     xf86CrtcConfigPtr  config = XF86_CRTC_CONFIG_PTR(scrn);
4201     int i, j;
4202     Bool found = FALSE;
4203     Bool changed = FALSE;
4204 
4205     /* Try to re-set the mode on all the connectors with a BAD link-state:
4206      * This may happen if a link degrades and a new modeset is necessary, using
4207      * different link-training parameters. If the kernel found that the current
4208      * mode is not achievable anymore, it should have pruned the mode before
4209      * sending the hotplug event. Try to re-set the currently-set mode to keep
4210      * the display alive, this will fail if the mode has been pruned.
4211      * In any case, we will send randr events for the Desktop Environment to
4212      * deal with it, if it wants to.
4213      */
4214     for (i = 0; i < config->num_output; i++) {
4215         xf86OutputPtr output = config->output[i];
4216         drmmode_output_private_ptr drmmode_output = output->driver_private;
4217         xf86CrtcPtr crtc = output->crtc;
4218 
4219         if (!crtc)
4220             continue;
4221 
4222         /* Update output status */
4223         if (drmmode_output_detect(output) == XF86OutputStatusDisconnected)
4224             continue;
4225 
4226         /* Get an updated view of the properties for the current connector and
4227          * look for the link-status property
4228          */
4229         for (j = 0; j < drmmode_output->num_props; j++) {
4230             drmmode_prop_ptr p = &drmmode_output->props[j];
4231 
4232             if (!strcmp(p->mode_prop->name, "link-status")) {
4233                 if (p->value == DRM_MODE_LINK_STATUS_BAD) {
4234                     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4235                     drmmode_crtc->need_modeset = TRUE;
4236 
4237                     /* Delay re-set to dpms-on */
4238                     if (drmmode_output->dpms != DPMSModeOn)
4239                         break;
4240 
4241                     /* the connector got a link failure, re-set the current mode */
4242                     drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
4243                                            crtc->x, crtc->y);
4244 
4245                     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
4246                                "hotplug event: connector %u's link-state is BAD, "
4247                                "tried resetting the current mode. You may be left"
4248                                "with a black screen if this fails...\n",
4249                                drmmode_output->mode_output->connector_id);
4250                 }
4251                 break;
4252             }
4253         }
4254     }
4255 
4256     mode_res = drmModeGetResources(drmmode->fd);
4257     if (!mode_res)
4258         goto out;
4259 
4260     if (mode_res->count_crtcs != config->num_crtc) {
4261         /* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
4262         goto out_free_res;
4263     }
4264 
4265     /* figure out if we have gotten rid of any connectors
4266        traverse old output list looking for outputs */
4267     for (i = 0; i < config->num_output; i++) {
4268         xf86OutputPtr output = config->output[i];
4269         drmmode_output_private_ptr drmmode_output;
4270 
4271         drmmode_output = output->driver_private;
4272         found = FALSE;
4273         for (j = 0; j < mode_res->count_connectors; j++) {
4274             if (mode_res->connectors[j] == drmmode_output->output_id) {
4275                 found = TRUE;
4276                 break;
4277             }
4278         }
4279         if (found)
4280             continue;
4281 
4282         drmModeFreeConnector(drmmode_output->mode_output);
4283         drmmode_output->mode_output = NULL;
4284         drmmode_output->output_id = -1;
4285 
4286         changed = TRUE;
4287     }
4288 
4289     /* find new output ids we don't have outputs for */
4290     for (i = 0; i < mode_res->count_connectors; i++) {
4291         found = FALSE;
4292 
4293         for (j = 0; j < config->num_output; j++) {
4294             xf86OutputPtr output = config->output[j];
4295             drmmode_output_private_ptr drmmode_output;
4296 
4297             drmmode_output = output->driver_private;
4298             if (mode_res->connectors[i] == drmmode_output->output_id) {
4299                 found = TRUE;
4300                 break;
4301             }
4302         }
4303         if (found)
4304             continue;
4305 
4306         changed = TRUE;
4307         drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
4308     }
4309 
4310     if (changed) {
4311         RRSetChanged(xf86ScrnToScreen(scrn));
4312         RRTellChanged(xf86ScrnToScreen(scrn));
4313     }
4314 
4315 out_free_res:
4316 
4317     /* Check to see if a lessee has disappeared */
4318     drmmode_validate_leases(scrn);
4319 
4320     drmModeFreeResources(mode_res);
4321 out:
4322     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
4323 }
4324 
4325 #undef DRM_MODE_LINK_STATUS_BAD
4326 #undef DRM_MODE_LINK_STATUS_GOOD
4327 
4328 #ifdef CONFIG_UDEV_KMS
4329 
4330 static void
drmmode_handle_uevents(int fd,void * closure)4331 drmmode_handle_uevents(int fd, void *closure)
4332 {
4333     drmmode_ptr drmmode = closure;
4334     struct udev_device *dev;
4335     Bool found = FALSE;
4336 
4337     while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
4338         udev_device_unref(dev);
4339         found = TRUE;
4340     }
4341     if (!found)
4342         return;
4343 
4344     drmmode_update_kms_state(drmmode);
4345 }
4346 
4347 #endif
4348 
4349 void
drmmode_uevent_init(ScrnInfoPtr scrn,drmmode_ptr drmmode)4350 drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
4351 {
4352 #ifdef CONFIG_UDEV_KMS
4353     struct udev *u;
4354     struct udev_monitor *mon;
4355 
4356     u = udev_new();
4357     if (!u)
4358         return;
4359     mon = udev_monitor_new_from_netlink(u, "udev");
4360     if (!mon) {
4361         udev_unref(u);
4362         return;
4363     }
4364 
4365     if (udev_monitor_filter_add_match_subsystem_devtype(mon,
4366                                                         "drm",
4367                                                         "drm_minor") < 0 ||
4368         udev_monitor_enable_receiving(mon) < 0) {
4369         udev_monitor_unref(mon);
4370         udev_unref(u);
4371         return;
4372     }
4373 
4374     drmmode->uevent_handler =
4375         xf86AddGeneralHandler(udev_monitor_get_fd(mon),
4376                               drmmode_handle_uevents, drmmode);
4377 
4378     drmmode->uevent_monitor = mon;
4379 #endif
4380 }
4381 
4382 void
drmmode_uevent_fini(ScrnInfoPtr scrn,drmmode_ptr drmmode)4383 drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
4384 {
4385 #ifdef CONFIG_UDEV_KMS
4386     if (drmmode->uevent_handler) {
4387         struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
4388 
4389         xf86RemoveGeneralHandler(drmmode->uevent_handler);
4390 
4391         udev_monitor_unref(drmmode->uevent_monitor);
4392         udev_unref(u);
4393     }
4394 #endif
4395 }
4396 
4397 /* create front and cursor BOs */
4398 Bool
drmmode_create_initial_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4399 drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4400 {
4401     modesettingPtr ms = modesettingPTR(pScrn);
4402     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4403     int width;
4404     int height;
4405     int bpp = ms->drmmode.kbpp;
4406     int i;
4407     int cpp = (bpp + 7) / 8;
4408 
4409     width = pScrn->virtualX;
4410     height = pScrn->virtualY;
4411 
4412     if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
4413         return FALSE;
4414     if (drmmode_bo_import(drmmode, &drmmode->front_bo, &drmmode->fb_id) < 0)
4415         return FALSE;
4416     pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
4417 
4418     width = ms->cursor_width;
4419     height = ms->cursor_height;
4420     bpp = 32;
4421     for (i = 0; i < xf86_config->num_crtc; i++) {
4422         xf86CrtcPtr crtc = xf86_config->crtc[i];
4423         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4424 
4425         drmmode_crtc->cursor_bo =
4426             dumb_bo_create(drmmode->fd, width, height, bpp);
4427     }
4428     return TRUE;
4429 }
4430 
4431 void *
drmmode_map_front_bo(drmmode_ptr drmmode)4432 drmmode_map_front_bo(drmmode_ptr drmmode)
4433 {
4434     return drmmode_bo_map(drmmode, &drmmode->front_bo);
4435 }
4436 
4437 void *
drmmode_map_slave_bo(drmmode_ptr drmmode,msPixmapPrivPtr ppriv)4438 drmmode_map_slave_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
4439 {
4440     int ret;
4441 
4442     if (ppriv->backing_bo->ptr)
4443         return ppriv->backing_bo->ptr;
4444 
4445     ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
4446     if (ret)
4447         return NULL;
4448 
4449     return ppriv->backing_bo->ptr;
4450 }
4451 
4452 Bool
drmmode_map_cursor_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4453 drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4454 {
4455     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4456     int i, ret;
4457 
4458     for (i = 0; i < xf86_config->num_crtc; i++) {
4459         xf86CrtcPtr crtc = xf86_config->crtc[i];
4460         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4461 
4462         ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
4463         if (ret)
4464             return FALSE;
4465     }
4466     return TRUE;
4467 }
4468 
4469 void
drmmode_free_bos(ScrnInfoPtr pScrn,drmmode_ptr drmmode)4470 drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
4471 {
4472     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
4473     int i;
4474 
4475     if (drmmode->fb_id) {
4476         drmModeRmFB(drmmode->fd, drmmode->fb_id);
4477         drmmode->fb_id = 0;
4478     }
4479 
4480     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
4481 
4482     for (i = 0; i < xf86_config->num_crtc; i++) {
4483         xf86CrtcPtr crtc = xf86_config->crtc[i];
4484         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4485 
4486         dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
4487         drmmode_destroy_flip_fb(crtc);
4488     }
4489 }
4490 
4491 /* ugly workaround to see if we can create 32bpp */
4492 void
drmmode_get_default_bpp(ScrnInfoPtr pScrn,drmmode_ptr drmmode,int * depth,int * bpp)4493 drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
4494                         int *bpp)
4495 {
4496     drmModeResPtr mode_res;
4497     uint64_t value;
4498     struct dumb_bo *bo;
4499     uint32_t fb_id;
4500     int ret;
4501 
4502     /* 16 is fine */
4503     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
4504     if (!ret && (value == 16 || value == 8)) {
4505         *depth = value;
4506         *bpp = value;
4507         return;
4508     }
4509 
4510     *depth = 24;
4511     mode_res = drmModeGetResources(drmmode->fd);
4512     if (!mode_res)
4513         return;
4514 
4515     if (mode_res->min_width == 0)
4516         mode_res->min_width = 1;
4517     if (mode_res->min_height == 0)
4518         mode_res->min_height = 1;
4519     /*create a bo */
4520     bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
4521                         32);
4522     if (!bo) {
4523         *bpp = 24;
4524         goto out;
4525     }
4526 
4527     ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
4528                        24, 32, bo->pitch, bo->handle, &fb_id);
4529 
4530     if (ret) {
4531         *bpp = 24;
4532         dumb_bo_destroy(drmmode->fd, bo);
4533         goto out;
4534     }
4535 
4536     drmModeRmFB(drmmode->fd, fb_id);
4537     *bpp = 32;
4538 
4539     dumb_bo_destroy(drmmode->fd, bo);
4540  out:
4541     drmModeFreeResources(mode_res);
4542     return;
4543 }
4544 
4545 /*
4546  * We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
4547  * is active. When a swcursor is active we disabe page-flipping.
4548  */
4549 
drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,ScrnInfoPtr scrn,int x,int y)4550 static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
4551                                          ScrnInfoPtr scrn, int x, int y)
4552 {
4553     modesettingPtr ms = modesettingPTR(scrn);
4554     CursorPtr cursor = sprite_priv->cursor;
4555     Bool sprite_visible = sprite_priv->sprite_visible;
4556 
4557     if (cursor) {
4558         x -= cursor->bits->xhot;
4559         y -= cursor->bits->yhot;
4560 
4561         sprite_priv->sprite_visible =
4562             x < scrn->virtualX && y < scrn->virtualY &&
4563             (x + cursor->bits->width > 0) &&
4564             (y + cursor->bits->height > 0);
4565     } else {
4566         sprite_priv->sprite_visible = FALSE;
4567     }
4568 
4569     ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
4570 }
4571 
drmmode_sprite_set_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor,int x,int y)4572 static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4573                                       CursorPtr pCursor, int x, int y)
4574 {
4575     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4576     modesettingPtr ms = modesettingPTR(scrn);
4577     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4578 
4579     sprite_priv->cursor = pCursor;
4580     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4581 
4582     ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
4583 }
4584 
drmmode_sprite_move_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,int x,int y)4585 static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
4586                                        int x, int y)
4587 {
4588     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4589     modesettingPtr ms = modesettingPTR(scrn);
4590     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
4591 
4592     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
4593 
4594     ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
4595 }
4596 
drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4597 static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
4598                                                   ScreenPtr pScreen,
4599                                                   CursorPtr pCursor)
4600 {
4601     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4602     modesettingPtr ms = modesettingPTR(scrn);
4603 
4604     return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
4605 }
4606 
drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,ScreenPtr pScreen,CursorPtr pCursor)4607 static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
4608                                                     ScreenPtr pScreen,
4609                                                     CursorPtr pCursor)
4610 {
4611     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4612     modesettingPtr ms = modesettingPTR(scrn);
4613 
4614     return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
4615 }
4616 
drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,ScreenPtr pScreen)4617 static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
4618                                                     ScreenPtr pScreen)
4619 {
4620     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4621     modesettingPtr ms = modesettingPTR(scrn);
4622 
4623     return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
4624 }
4625 
drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,ScreenPtr pScreen)4626 static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
4627                                                  ScreenPtr pScreen)
4628 {
4629     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
4630     modesettingPtr ms = modesettingPTR(scrn);
4631 
4632     ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
4633 }
4634 
4635 miPointerSpriteFuncRec drmmode_sprite_funcs = {
4636     .RealizeCursor = drmmode_sprite_realize_realize_cursor,
4637     .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
4638     .SetCursor = drmmode_sprite_set_cursor,
4639     .MoveCursor = drmmode_sprite_move_cursor,
4640     .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
4641     .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
4642 };
4643 
4644 static void
drmmode_destroy_flip_fb(xf86CrtcPtr crtc)4645 drmmode_destroy_flip_fb(xf86CrtcPtr crtc)
4646 {
4647     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4648     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4649     int i;
4650 
4651     for (i = 0; i < ARRAY_SIZE(drmmode_crtc->flip_fb); i++) {
4652         drmmode_fb *fb = &drmmode_crtc->flip_fb[i];
4653 
4654         if (fb->fb_id)
4655             drmModeRmFB(drmmode->fd, fb->fb_id);
4656         fb->fb_id = 0;
4657 
4658         drmmode_bo_destroy(drmmode, &fb->bo);
4659 
4660         if (fb->pixmap)
4661             fb->pixmap->drawable.pScreen->DestroyPixmap(fb->pixmap);
4662         fb->pixmap = NULL;
4663 
4664         if (fb->damage)
4665             DamageDestroy(fb->damage);
4666         fb->damage = NULL;
4667     }
4668 }
4669 
4670 static Bool
drmmode_create_flip_fb(xf86CrtcPtr crtc)4671 drmmode_create_flip_fb(xf86CrtcPtr crtc)
4672 {
4673     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4674     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4675     int i, width, height, bpp;
4676 
4677     width = crtc->mode.HDisplay;
4678     height = crtc->mode.VDisplay;
4679     bpp = drmmode->kbpp;
4680 
4681     drmmode_destroy_flip_fb(crtc);
4682 
4683     for (i = 0; i < ARRAY_SIZE(drmmode_crtc->flip_fb); i++) {
4684         drmmode_fb *fb = &drmmode_crtc->flip_fb[i];
4685 
4686         if (!drmmode_create_bo(drmmode, &fb->bo, width, height, bpp))
4687             goto fail;
4688 
4689         if (drmmode_bo_import(drmmode, &fb->bo, &fb->fb_id) < 0)
4690             goto fail;
4691     }
4692 
4693     return TRUE;
4694 
4695 fail:
4696     drmmode_destroy_flip_fb(crtc);
4697     return FALSE;
4698 }
4699 
4700 static Bool
drmmode_apply_transform(xf86CrtcPtr crtc)4701 drmmode_apply_transform(xf86CrtcPtr crtc)
4702 {
4703     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4704     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4705     BoxRec box = {
4706         .x1 = 0,
4707         .y1 = 0,
4708         .x2 = crtc->mode.HDisplay,
4709         .y2 = crtc->mode.VDisplay,
4710     };
4711     int w, h;
4712 
4713     /* should always success */
4714     xf86CrtcRotate(crtc);
4715 
4716     pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, &box);
4717     w = box.x2 - box.x1;
4718     h = box.y2 - box.y1;
4719 
4720     if ((w == crtc->mode.HDisplay && h == crtc->mode.VDisplay) ||
4721         (w == crtc->mode.VDisplay && h == crtc->mode.HDisplay))
4722         drmmode_crtc->is_scale = FALSE;
4723     else
4724         drmmode_crtc->is_scale = TRUE;
4725 
4726     /* fb flipping disabled or doing shared pixmap flipping */
4727     if (!drmmode_crtc->can_flip_fb || drmmode_crtc->enable_flipping)
4728         goto bail;
4729 
4730     crtc->driverIsPerformingTransform |= XF86DriverTransformOutput;
4731 
4732     /* should always success */
4733     xf86CrtcRotate(crtc);
4734 
4735     if (!crtc->transform_in_use) {
4736         crtc->driverIsPerformingTransform &= ~XF86DriverTransformOutput;
4737 
4738         if (drmmode->fb_flip_mode == DRMMODE_FB_FLIP_TRANSFORMED)
4739             goto bail;
4740     }
4741 
4742     if (!drmmode_create_flip_fb(crtc)) {
4743         drmmode_crtc->can_flip_fb = FALSE;
4744         goto fail;
4745     }
4746 
4747     drmmode_crtc->flip_fb_enabled = TRUE;
4748 
4749     return TRUE;
4750 
4751 fail:
4752     drmmode_crtc->can_flip_fb = FALSE;
4753 
4754 bail:
4755     drmmode_destroy_flip_fb(crtc);
4756     drmmode_crtc->flip_fb_enabled = FALSE;
4757 
4758     crtc->driverIsPerformingTransform &= ~XF86DriverTransformOutput;
4759     return xf86CrtcRotate(crtc);
4760 }
4761 
4762 static void
drmmode_flip_damage_destroy(DamagePtr damage,void * closure)4763 drmmode_flip_damage_destroy(DamagePtr damage, void *closure)
4764 {
4765     drmmode_fb *fb = closure;
4766 
4767     if (fb->pixmap)
4768         fb->pixmap->drawable.pScreen->DestroyPixmap(fb->pixmap);
4769     fb->pixmap = NULL;
4770 
4771     fb->damage = NULL;
4772 }
4773 
4774 static RegionPtr
drmmode_transform_region(xf86CrtcPtr crtc,RegionPtr src)4775 drmmode_transform_region(xf86CrtcPtr crtc, RegionPtr src)
4776 {
4777 #define MS_MAX_NUM_BOX 4
4778     RegionPtr region = RegionCreate(NULL, 0);
4779     BoxRec rects[MS_MAX_NUM_BOX];
4780     BoxPtr box, rect;
4781     Bool empty;
4782     int n, i;
4783 
4784     if (!RegionNotEmpty(src))
4785         return region;
4786 
4787     if (RegionNumRects(src) < MS_MAX_NUM_BOX) {
4788         n = RegionNumRects(src);
4789         box = RegionRects(src);
4790     } else {
4791         /* draw the extents rather than small rects */
4792         n = 1;
4793         box = RegionExtents(src);
4794     }
4795 
4796     empty = TRUE;
4797     for (i = 0; i < n; i++) {
4798         rect = &rects[i];
4799 
4800         rect->x1 = box[i].x1 - crtc->filter_width / 2;
4801         rect->x2 = box[i].x2 + crtc->filter_width / 2;
4802         rect->y1 = box[i].y1 - crtc->filter_height / 2;
4803         rect->y2 = box[i].y2 + crtc->filter_height / 2;
4804         pixman_f_transform_bounds(&crtc->f_framebuffer_to_crtc, rect);
4805         rect->x1 = max(rect->x1, 0);
4806         rect->y1 = max(rect->y1, 0);
4807         rect->x2 = min(rect->x2, crtc->mode.HDisplay);
4808         rect->y2 = min(rect->y2, crtc->mode.VDisplay);
4809 
4810         if (rect->x1 < rect->x2 && rect->y1 < rect->y2)
4811             empty = FALSE;
4812     }
4813 
4814     if (empty)
4815         return region;
4816 
4817     RegionInitBoxes(region, rects, n);
4818     return region;
4819 }
4820 
4821 Bool
ms_copy_area(PixmapPtr pSrc,PixmapPtr pDst,pixman_f_transform_t * transform,RegionPtr clip)4822 ms_copy_area(PixmapPtr pSrc, PixmapPtr pDst,
4823              pixman_f_transform_t *transform, RegionPtr clip)
4824 {
4825     ScreenPtr screen = pSrc->drawable.pScreen;
4826     PictFormatPtr format = PictureWindowFormat(screen->root);
4827     PicturePtr src = NULL, dst = NULL;
4828     pixman_transform_t t;
4829     Bool ret = FALSE;
4830     BoxPtr box;
4831     int n, error;
4832 
4833     src = CreatePicture(None, &pSrc->drawable,
4834                         format, 0L, NULL, serverClient, &error);
4835     if (!src)
4836         return FALSE;
4837 
4838     dst = CreatePicture(None, &pDst->drawable,
4839                         format, 0L, NULL, serverClient, &error);
4840     if (!dst)
4841         goto out;
4842 
4843     if (transform) {
4844         if (!pixman_transform_from_pixman_f_transform(&t, transform))
4845             goto out;
4846 
4847         error = SetPictureTransform(src, &t);
4848         if (error)
4849             goto out;
4850     }
4851 
4852     box = REGION_RECTS(clip);
4853     n = REGION_NUM_RECTS(clip);
4854 
4855     while (n--) {
4856         CompositePicture(PictOpSrc,
4857                          src, NULL, dst,
4858                          box->x1, box->y1, 0, 0, box->x1,
4859                          box->y1, box->x2 - box->x1,
4860                          box->y2 - box->y1);
4861 
4862         box++;
4863     }
4864 
4865     ret = TRUE;
4866 out:
4867     if (src)
4868         FreePicture(src, None);
4869     if (dst)
4870         FreePicture(dst, None);
4871 
4872     return ret;
4873 }
4874 
4875 static Bool
drmmode_update_fb(xf86CrtcPtr crtc,drmmode_fb * fb)4876 drmmode_update_fb(xf86CrtcPtr crtc, drmmode_fb *fb)
4877 {
4878     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4879     ScrnInfoPtr scrn = crtc->scrn;
4880     modesettingPtr ms = modesettingPTR(scrn);
4881     drmmode_ptr drmmode = &ms->drmmode;
4882     ScreenPtr screen = xf86ScrnToScreen(scrn);
4883     SourceValidateProcPtr SourceValidate = screen->SourceValidate;
4884     RegionPtr dirty;
4885     Bool ret;
4886 
4887     if (!fb->pixmap) {
4888         void *data = drmmode_bo_map(&ms->drmmode, &fb->bo);
4889         int pitch = drmmode_bo_get_pitch(&fb->bo);
4890         fb->pixmap = drmmode_create_pixmap_header(screen,
4891                                                   fb->bo.width,
4892                                                   fb->bo.height,
4893                                                   scrn->depth,
4894                                                   ms->drmmode.kbpp,
4895                                                   pitch, data);
4896         if (!fb->pixmap)
4897             return FALSE;
4898 
4899         if (!drmmode_set_pixmap_bo(&ms->drmmode, fb->pixmap, &fb->bo))
4900             return FALSE;
4901 
4902         /* setup a damage to track dirty */
4903         fb->damage = DamageCreate(NULL, drmmode_flip_damage_destroy,
4904                                   DamageReportNone, TRUE, screen, fb);
4905         DamageRegister(&screen->root->drawable, fb->damage);
4906 
4907         fb->need_clear = TRUE;
4908     }
4909 
4910     /* scaled screens may not be able to map areas(due to precision) */
4911     if (drmmode_crtc->is_scale && drmmode->exa)
4912         fb->need_clear = TRUE;
4913 
4914     dirty = NULL;
4915     if (fb->need_clear) {
4916         BoxRec rect = {
4917             .x1 = 0,
4918             .y1 = 0,
4919             .x2 = crtc->mode.HDisplay,
4920             .y2 = crtc->mode.VDisplay,
4921         };
4922 
4923         dirty = RegionCreate(&rect, 1);
4924     } else {
4925         RegionPtr region = DamageRegion(fb->damage);
4926 
4927         dirty = drmmode_transform_region(crtc, region);
4928     }
4929 
4930     if (!RegionNotEmpty(dirty)) {
4931         ret = TRUE;
4932         goto out;
4933     }
4934 
4935     screen->SourceValidate = miSourceValidate;
4936     if (drmmode->exa)
4937         ret = ms_exa_copy_area(screen->GetScreenPixmap(screen), fb->pixmap,
4938                                &crtc->f_crtc_to_framebuffer, dirty);
4939     else
4940         ret = ms_copy_area(screen->GetScreenPixmap(screen), fb->pixmap,
4941                            &crtc->f_crtc_to_framebuffer, dirty);
4942     screen->SourceValidate = SourceValidate;
4943 
4944 #ifdef GLAMOR_HAS_GBM
4945     if (ms->drmmode.glamor)
4946         glamor_finish(screen);
4947 #endif
4948 
4949     fb->need_clear = FALSE;
4950     DamageEmpty(fb->damage);
4951 
4952     ret = TRUE;
4953 out:
4954     RegionDestroy(dirty);
4955     return ret;
4956 }
4957 
4958 static void
drmmode_flip_fb_handler(modesettingPtr ms,uint64_t msc,uint64_t ust,void * data)4959 drmmode_flip_fb_handler(modesettingPtr ms, uint64_t msc,
4960                         uint64_t ust, void *data)
4961 {
4962     drmmode_crtc_private_ptr drmmode_crtc = data;
4963 
4964     drmmode_crtc->flipping = FALSE;
4965 }
4966 
4967 static void
drmmode_flip_fb_abort(modesettingPtr ms,void * data)4968 drmmode_flip_fb_abort(modesettingPtr ms, void *data)
4969 {
4970     drmmode_crtc_private_ptr drmmode_crtc = data;
4971 
4972     drmmode_crtc->flipping = FALSE;
4973 }
4974 
4975 Bool
drmmode_flip_fb(xf86CrtcPtr crtc,int * timeout)4976 drmmode_flip_fb(xf86CrtcPtr crtc, int *timeout)
4977 {
4978     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
4979     drmmode_ptr drmmode = drmmode_crtc->drmmode;
4980     ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
4981     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
4982     modesettingPtr ms = modesettingPTR(scrn);
4983     drmmode_fb *fb;
4984     struct timeval tv;
4985     uint64_t now_ms, diff_ms;
4986     int next_fb;
4987 
4988     if (!drmmode_crtc || !crtc->active || !drmmode_crtc_connected(crtc) ||
4989         drmmode_crtc->dpms_mode != DPMSModeOn || drmmode_crtc->rotate_fb_id)
4990         return TRUE;
4991 
4992     if (!drmmode_crtc->flip_fb_enabled)
4993         return TRUE;
4994 
4995     gettimeofday(&tv, NULL);
4996     now_ms = tv.tv_sec * 1000 + tv.tv_usec / 1000;
4997 
4998     diff_ms = now_ms - drmmode_crtc->flipping_time_ms;
4999 
5000     /* handle flip timeout */
5001     if (drmmode_crtc->flipping && diff_ms >= 50) {
5002         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5003                    "crtc-%d flip timeout!\n", drmmode_crtc->mode_crtc->crtc_id);
5004         drmmode_crtc->flipping = FALSE;
5005     }
5006 
5007     /* retry later if still flipping */
5008     if (drmmode_crtc->flipping ||
5009         drmmode->dri2_flipping || drmmode->present_flipping)
5010         goto retry;
5011 
5012     if (drmmode_crtc->external_flipped) {
5013         /* delay to exit external flip mode */
5014         if (diff_ms < 100)
5015             goto retry;
5016     } else if (drmmode->fb_flip_rate) {
5017         /* limit flip rate */
5018         if (diff_ms < (1000 / drmmode->fb_flip_rate))
5019             goto retry;
5020     }
5021 
5022     /* keep the current fb if not dirty */
5023     fb = &drmmode_crtc->flip_fb[drmmode_crtc->current_fb];
5024     if (fb->damage && !fb->need_clear) {
5025         RegionPtr region = DamageRegion(fb->damage);
5026         RegionPtr dirty;
5027         Bool ret;
5028 
5029         dirty = drmmode_transform_region(crtc, region);
5030         if (dirty) {
5031             ret = RegionNotEmpty(dirty);
5032             RegionDestroy(dirty);
5033             if (!ret)
5034                 return TRUE;
5035         }
5036     }
5037 
5038     /* switch to the next fb */
5039     next_fb = drmmode_crtc->current_fb + 1;
5040     next_fb %= ARRAY_SIZE(drmmode_crtc->flip_fb);
5041     fb = &drmmode_crtc->flip_fb[next_fb];
5042     if (!drmmode_update_fb(crtc, fb)) {
5043         xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5044                    "crtc-%d failed to update fb!\n",
5045                    drmmode_crtc->mode_crtc->crtc_id);
5046         return FALSE;
5047     }
5048 
5049     if (!ms_do_pageflip_bo(screen, &fb->bo, drmmode_crtc,
5050                            drmmode_crtc->vblank_pipe, crtc, ms->async_pageflip,
5051                            drmmode_flip_fb_handler, drmmode_flip_fb_abort)) {
5052         /* HACK: Workaround commit random interrupted case */
5053         if (errno != EPERM) {
5054             xf86DrvMsg(drmmode->scrn->scrnIndex, X_WARNING,
5055                        "crtc-%d failed to flip(%s)!\n",
5056                        drmmode_crtc->mode_crtc->crtc_id, strerror(errno));
5057             return FALSE;
5058         }
5059     }
5060 
5061     drmmode_crtc->current_fb = next_fb;
5062 
5063     drmmode_crtc->flipping = TRUE;
5064     drmmode_crtc->external_flipped = FALSE;
5065 
5066     /* take out FB syncing time from framerate control */
5067     drmmode_crtc->flipping_time_ms = now_ms;
5068 
5069     return TRUE;
5070 
5071 retry:
5072     if (*timeout)
5073         *timeout = 3;
5074     return TRUE;
5075 }
5076