xserver

xserver with xephyr scale patch
git clone https://git.neptards.moe/u3shit/xserver.git
Log | Files | Refs | README | LICENSE

drmmode_display.c (136376B)


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