Home | History | Annotate | Line # | Download | only in modesetting
      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 (at) redhat.com>
     26  *    Aaron Plattner <aplattner (at) 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     1ULL << 32, 0, 0,
     67     0, 1ULL << 32, 0,
     68     0, 0, 1ULL << 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 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(xf86CrtcPtr crtc,
   1740                       uint16_t * red, uint16_t * green, uint16_t * blue,
   1741                       int size)
   1742 {
   1743     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1744     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1745     drmmode_prop_info_ptr gamma_lut_info =
   1746         &drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT];
   1747     const uint32_t crtc_id = drmmode_crtc->mode_crtc->crtc_id;
   1748     uint32_t blob_id;
   1749     struct drm_color_lut *lut = malloc(sizeof(*lut) * size);
   1750 
   1751     if (lut == NULL) {
   1752         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
   1753                    "Failed to allocate memory for %d LUT entries.\n", size);
   1754 	return;
   1755     }
   1756 
   1757     assert(gamma_lut_info->prop_id != 0);
   1758 
   1759     for (int i = 0; i < size; i++) {
   1760         lut[i].red = red[i];
   1761         lut[i].green = green[i];
   1762         lut[i].blue = blue[i];
   1763     }
   1764 
   1765     if (!drmModeCreatePropertyBlob(drmmode->fd, lut, sizeof(lut), &blob_id)) {
   1766 
   1767         drmModeObjectSetProperty(drmmode->fd, crtc_id, DRM_MODE_OBJECT_CRTC,
   1768                                  gamma_lut_info->prop_id, blob_id);
   1769 
   1770         drmModeDestroyPropertyBlob(drmmode->fd, blob_id);
   1771     }
   1772     free(lut);
   1773 }
   1774 
   1775 static void
   1776 drmmode_crtc_gamma_set(xf86CrtcPtr crtc, uint16_t * red, uint16_t * green,
   1777                        uint16_t * blue, int size)
   1778 {
   1779     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1780     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1781 
   1782     if (drmmode_crtc->use_gamma_lut) {
   1783         drmmode_set_gamma_lut(crtc, red, green, blue, size);
   1784     } else {
   1785         drmModeCrtcSetGamma(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
   1786                             size, red, green, blue);
   1787     }
   1788 }
   1789 
   1790 static Bool
   1791 drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
   1792                                       PixmapPtr *target)
   1793 {
   1794     ScreenPtr screen = xf86ScrnToScreen(crtc->scrn);
   1795     PixmapPtr screenpix = screen->GetScreenPixmap(screen);
   1796     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
   1797     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1798     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1799     int c, total_width = 0, max_height = 0, this_x = 0;
   1800 
   1801     if (*target) {
   1802         PixmapStopDirtyTracking(&(*target)->drawable, screenpix);
   1803         if (drmmode->fb_id) {
   1804             drmModeRmFB(drmmode->fd, drmmode->fb_id);
   1805             drmmode->fb_id = 0;
   1806         }
   1807         drmmode_crtc->prime_pixmap_x = 0;
   1808         *target = NULL;
   1809     }
   1810 
   1811     if (!ppix)
   1812         return TRUE;
   1813 
   1814     /* iterate over all the attached crtcs to work out the bounding box */
   1815     for (c = 0; c < xf86_config->num_crtc; c++) {
   1816         xf86CrtcPtr iter = xf86_config->crtc[c];
   1817         if (!iter->enabled && iter != crtc)
   1818             continue;
   1819         if (iter == crtc) {
   1820             this_x = total_width;
   1821             total_width += ppix->drawable.width;
   1822             if (max_height < ppix->drawable.height)
   1823                 max_height = ppix->drawable.height;
   1824         } else {
   1825             total_width += iter->mode.HDisplay;
   1826             if (max_height < iter->mode.VDisplay)
   1827                 max_height = iter->mode.VDisplay;
   1828         }
   1829     }
   1830 
   1831     if (total_width != screenpix->drawable.width ||
   1832         max_height != screenpix->drawable.height) {
   1833 
   1834         if (!drmmode_xf86crtc_resize(crtc->scrn, total_width, max_height))
   1835             return FALSE;
   1836 
   1837         screenpix = screen->GetScreenPixmap(screen);
   1838         screen->width = screenpix->drawable.width = total_width;
   1839         screen->height = screenpix->drawable.height = max_height;
   1840     }
   1841     drmmode_crtc->prime_pixmap_x = this_x;
   1842     PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
   1843                              RR_Rotate_0);
   1844     *target = ppix;
   1845     return TRUE;
   1846 }
   1847 
   1848 static Bool
   1849 drmmode_set_target_scanout_pixmap_cpu(xf86CrtcPtr crtc, PixmapPtr ppix,
   1850                                       PixmapPtr *target)
   1851 {
   1852     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1853     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1854     msPixmapPrivPtr ppriv;
   1855     void *ptr;
   1856 
   1857     if (*target) {
   1858         ppriv = msGetPixmapPriv(drmmode, *target);
   1859         drmModeRmFB(drmmode->fd, ppriv->fb_id);
   1860         ppriv->fb_id = 0;
   1861         if (ppriv->secondary_damage) {
   1862             DamageUnregister(ppriv->secondary_damage);
   1863             ppriv->secondary_damage = NULL;
   1864         }
   1865         *target = NULL;
   1866     }
   1867 
   1868     if (!ppix)
   1869         return TRUE;
   1870 
   1871     ppriv = msGetPixmapPriv(drmmode, ppix);
   1872     if (!ppriv->secondary_damage) {
   1873         ppriv->secondary_damage = DamageCreate(NULL, NULL,
   1874                                            DamageReportNone,
   1875                                            TRUE,
   1876                                            crtc->randr_crtc->pScreen,
   1877                                            NULL);
   1878     }
   1879     ptr = drmmode_map_secondary_bo(drmmode, ppriv);
   1880     ppix->devPrivate.ptr = ptr;
   1881     DamageRegister(&ppix->drawable, ppriv->secondary_damage);
   1882 
   1883     if (ppriv->fb_id == 0) {
   1884         int ret = drmModeAddFB(drmmode->fd, ppix->drawable.width,
   1885                      ppix->drawable.height,
   1886                      ppix->drawable.depth,
   1887                      ppix->drawable.bitsPerPixel,
   1888                      ppix->devKind, ppriv->backing_bo->handle, &ppriv->fb_id);
   1889 	if (ret) {
   1890 	    ErrorF("failed to set scanout pixmap cpu\n");
   1891 	    return FALSE;
   1892 	}
   1893     }
   1894     *target = ppix;
   1895     return TRUE;
   1896 }
   1897 
   1898 static Bool
   1899 drmmode_set_target_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix,
   1900                                   PixmapPtr *target)
   1901 {
   1902     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1903     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1904 
   1905     if (drmmode->reverse_prime_offload_mode)
   1906         return drmmode_set_target_scanout_pixmap_gpu(crtc, ppix, target);
   1907     else
   1908         return drmmode_set_target_scanout_pixmap_cpu(crtc, ppix, target);
   1909 }
   1910 
   1911 static Bool
   1912 drmmode_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr ppix)
   1913 {
   1914     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1915 
   1916     /* Use DisableSharedPixmapFlipping before switching to single buf */
   1917     if (drmmode_crtc->enable_flipping)
   1918         return FALSE;
   1919 
   1920     return drmmode_set_target_scanout_pixmap(crtc, ppix,
   1921                                              &drmmode_crtc->prime_pixmap);
   1922 }
   1923 
   1924 static void
   1925 drmmode_clear_pixmap(PixmapPtr pixmap)
   1926 {
   1927     ScreenPtr screen = pixmap->drawable.pScreen;
   1928     GCPtr gc;
   1929 #ifdef GLAMOR_HAS_GBM
   1930     modesettingPtr ms = modesettingPTR(xf86ScreenToScrn(screen));
   1931 
   1932     if (ms->drmmode.glamor) {
   1933         ms->glamor.clear_pixmap(pixmap);
   1934         return;
   1935     }
   1936 #endif
   1937 
   1938     gc = GetScratchGC(pixmap->drawable.depth, screen);
   1939     if (gc) {
   1940         miClearDrawable(&pixmap->drawable, gc);
   1941         FreeScratchGC(gc);
   1942     }
   1943 }
   1944 
   1945 static void *
   1946 drmmode_shadow_allocate(xf86CrtcPtr crtc, int width, int height)
   1947 {
   1948     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   1949     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   1950     int ret;
   1951 
   1952     if (!drmmode_create_bo(drmmode, &drmmode_crtc->rotate_bo,
   1953                            width, height, drmmode->kbpp)) {
   1954         xf86DrvMsg(crtc->scrn->scrnIndex, X_ERROR,
   1955                "Couldn't allocate shadow memory for rotated CRTC\n");
   1956         return NULL;
   1957     }
   1958 
   1959     ret = drmmode_bo_import(drmmode, &drmmode_crtc->rotate_bo,
   1960                             &drmmode_crtc->rotate_fb_id);
   1961 
   1962     if (ret) {
   1963         ErrorF("failed to add rotate fb\n");
   1964         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
   1965         return NULL;
   1966     }
   1967 
   1968 #ifdef GLAMOR_HAS_GBM
   1969     if (drmmode->gbm)
   1970         return drmmode_crtc->rotate_bo.gbm;
   1971 #endif
   1972     return drmmode_crtc->rotate_bo.dumb;
   1973 }
   1974 
   1975 static PixmapPtr
   1976 drmmode_create_pixmap_header(ScreenPtr pScreen, int width, int height,
   1977                              int depth, int bitsPerPixel, int devKind,
   1978                              void *pPixData)
   1979 {
   1980     PixmapPtr pixmap;
   1981 
   1982     /* width and height of 0 means don't allocate any pixmap data */
   1983     pixmap = (*pScreen->CreatePixmap)(pScreen, 0, 0, depth, 0);
   1984 
   1985     if (pixmap) {
   1986         if ((*pScreen->ModifyPixmapHeader)(pixmap, width, height, depth,
   1987                                            bitsPerPixel, devKind, pPixData))
   1988             return pixmap;
   1989         (*pScreen->DestroyPixmap)(pixmap);
   1990     }
   1991     return NullPixmap;
   1992 }
   1993 
   1994 static Bool
   1995 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo);
   1996 
   1997 static PixmapPtr
   1998 drmmode_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height)
   1999 {
   2000     ScrnInfoPtr scrn = crtc->scrn;
   2001     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2002     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   2003     uint32_t rotate_pitch;
   2004     PixmapPtr rotate_pixmap;
   2005     void *pPixData = NULL;
   2006 
   2007     if (!data) {
   2008         data = drmmode_shadow_allocate(crtc, width, height);
   2009         if (!data) {
   2010             xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   2011                        "Couldn't allocate shadow pixmap for rotated CRTC\n");
   2012             return NULL;
   2013         }
   2014     }
   2015 
   2016     if (!drmmode_bo_has_bo(&drmmode_crtc->rotate_bo)) {
   2017         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   2018                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
   2019         return NULL;
   2020     }
   2021 
   2022     pPixData = drmmode_bo_map(drmmode, &drmmode_crtc->rotate_bo);
   2023     rotate_pitch = drmmode_bo_get_pitch(&drmmode_crtc->rotate_bo);
   2024 
   2025     rotate_pixmap = drmmode_create_pixmap_header(scrn->pScreen,
   2026                                                  width, height,
   2027                                                  scrn->depth,
   2028                                                  drmmode->kbpp,
   2029                                                  rotate_pitch,
   2030                                                  pPixData);
   2031 
   2032     if (rotate_pixmap == NULL) {
   2033         xf86DrvMsg(scrn->scrnIndex, X_ERROR,
   2034                    "Couldn't allocate shadow pixmap for rotated CRTC\n");
   2035         return NULL;
   2036     }
   2037 
   2038     drmmode_set_pixmap_bo(drmmode, rotate_pixmap, &drmmode_crtc->rotate_bo);
   2039 
   2040     return rotate_pixmap;
   2041 }
   2042 
   2043 static void
   2044 drmmode_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data)
   2045 {
   2046     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2047     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   2048 
   2049     if (rotate_pixmap) {
   2050         rotate_pixmap->drawable.pScreen->DestroyPixmap(rotate_pixmap);
   2051     }
   2052 
   2053     if (data) {
   2054         drmModeRmFB(drmmode->fd, drmmode_crtc->rotate_fb_id);
   2055         drmmode_crtc->rotate_fb_id = 0;
   2056 
   2057         drmmode_bo_destroy(drmmode, &drmmode_crtc->rotate_bo);
   2058         memset(&drmmode_crtc->rotate_bo, 0, sizeof drmmode_crtc->rotate_bo);
   2059     }
   2060 }
   2061 
   2062 static void
   2063 drmmode_crtc_destroy(xf86CrtcPtr crtc)
   2064 {
   2065     drmmode_mode_ptr iterator, next;
   2066     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2067     modesettingPtr ms = modesettingPTR(crtc->scrn);
   2068 
   2069     if (!ms->atomic_modeset)
   2070         return;
   2071 
   2072     drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
   2073     xorg_list_for_each_entry_safe(iterator, next, &drmmode_crtc->mode_list, entry) {
   2074         drm_mode_destroy(crtc, iterator);
   2075     }
   2076 }
   2077 
   2078 static const xf86CrtcFuncsRec drmmode_crtc_funcs = {
   2079     .dpms = drmmode_crtc_dpms,
   2080     .set_mode_major = drmmode_set_mode_major,
   2081     .set_cursor_colors = drmmode_set_cursor_colors,
   2082     .set_cursor_position = drmmode_set_cursor_position,
   2083     .show_cursor_check = drmmode_show_cursor,
   2084     .hide_cursor = drmmode_hide_cursor,
   2085     .load_cursor_argb_check = drmmode_load_cursor_argb_check,
   2086 
   2087     .gamma_set = drmmode_crtc_gamma_set,
   2088     .destroy = drmmode_crtc_destroy,
   2089     .set_scanout_pixmap = drmmode_set_scanout_pixmap,
   2090     .shadow_allocate = drmmode_shadow_allocate,
   2091     .shadow_create = drmmode_shadow_create,
   2092     .shadow_destroy = drmmode_shadow_destroy,
   2093 };
   2094 
   2095 static uint32_t
   2096 drmmode_crtc_vblank_pipe(int crtc_id)
   2097 {
   2098     if (crtc_id > 1)
   2099         return crtc_id << DRM_VBLANK_HIGH_CRTC_SHIFT;
   2100     else if (crtc_id > 0)
   2101         return DRM_VBLANK_SECONDARY;
   2102     else
   2103         return 0;
   2104 }
   2105 
   2106 static Bool
   2107 is_plane_assigned(ScrnInfoPtr scrn, int plane_id)
   2108 {
   2109     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   2110     int c;
   2111 
   2112     for (c = 0; c < xf86_config->num_crtc; c++) {
   2113         xf86CrtcPtr iter = xf86_config->crtc[c];
   2114         drmmode_crtc_private_ptr drmmode_crtc = iter->driver_private;
   2115         if (drmmode_crtc->plane_id == plane_id)
   2116             return TRUE;
   2117     }
   2118 
   2119     return FALSE;
   2120 }
   2121 
   2122 /**
   2123  * Populates the formats array, and the modifiers of each format for a drm_plane.
   2124  */
   2125 static Bool
   2126 populate_format_modifiers(xf86CrtcPtr crtc, const drmModePlane *kplane,
   2127                           uint32_t blob_id)
   2128 {
   2129     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2130     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   2131     unsigned i, j;
   2132     drmModePropertyBlobRes *blob;
   2133     struct drm_format_modifier_blob *fmt_mod_blob;
   2134     uint32_t *blob_formats;
   2135     struct drm_format_modifier *blob_modifiers;
   2136 
   2137     if (!blob_id)
   2138         return FALSE;
   2139 
   2140     blob = drmModeGetPropertyBlob(drmmode->fd, blob_id);
   2141     if (!blob)
   2142         return FALSE;
   2143 
   2144     fmt_mod_blob = blob->data;
   2145     blob_formats = formats_ptr(fmt_mod_blob);
   2146     blob_modifiers = modifiers_ptr(fmt_mod_blob);
   2147 
   2148     assert(drmmode_crtc->num_formats == fmt_mod_blob->count_formats);
   2149 
   2150     for (i = 0; i < fmt_mod_blob->count_formats; i++) {
   2151         uint32_t num_modifiers = 0;
   2152         uint64_t *modifiers = NULL;
   2153         uint64_t *tmp;
   2154         for (j = 0; j < fmt_mod_blob->count_modifiers; j++) {
   2155             struct drm_format_modifier *mod = &blob_modifiers[j];
   2156 
   2157             if ((i < mod->offset) || (i > mod->offset + 63))
   2158                 continue;
   2159             if (!(mod->formats & (1 << (i - mod->offset))))
   2160                 continue;
   2161 
   2162             num_modifiers++;
   2163             tmp = realloc(modifiers, num_modifiers * sizeof(modifiers[0]));
   2164             if (!tmp) {
   2165                 free(modifiers);
   2166                 drmModeFreePropertyBlob(blob);
   2167                 return FALSE;
   2168             }
   2169             modifiers = tmp;
   2170             modifiers[num_modifiers - 1] = mod->modifier;
   2171         }
   2172 
   2173         drmmode_crtc->formats[i].format = blob_formats[i];
   2174         drmmode_crtc->formats[i].modifiers = modifiers;
   2175         drmmode_crtc->formats[i].num_modifiers = num_modifiers;
   2176     }
   2177 
   2178     drmModeFreePropertyBlob(blob);
   2179 
   2180     return TRUE;
   2181 }
   2182 
   2183 static void
   2184 drmmode_crtc_create_planes(xf86CrtcPtr crtc, int num)
   2185 {
   2186     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2187     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   2188     drmModePlaneRes *kplane_res;
   2189     drmModePlane *kplane, *best_kplane = NULL;
   2190     drmModeObjectProperties *props;
   2191     uint32_t i, type, blob_id;
   2192     int current_crtc, best_plane = 0;
   2193 
   2194     static drmmode_prop_enum_info_rec plane_type_enums[] = {
   2195         [DRMMODE_PLANE_TYPE_PRIMARY] = {
   2196             .name = "Primary",
   2197         },
   2198         [DRMMODE_PLANE_TYPE_OVERLAY] = {
   2199             .name = "Overlay",
   2200         },
   2201         [DRMMODE_PLANE_TYPE_CURSOR] = {
   2202             .name = "Cursor",
   2203         },
   2204     };
   2205     static const drmmode_prop_info_rec plane_props[] = {
   2206         [DRMMODE_PLANE_TYPE] = {
   2207             .name = "type",
   2208             .enum_values = plane_type_enums,
   2209             .num_enum_values = DRMMODE_PLANE_TYPE__COUNT,
   2210         },
   2211         [DRMMODE_PLANE_FB_ID] = { .name = "FB_ID", },
   2212         [DRMMODE_PLANE_CRTC_ID] = { .name = "CRTC_ID", },
   2213         [DRMMODE_PLANE_IN_FORMATS] = { .name = "IN_FORMATS", },
   2214         [DRMMODE_PLANE_SRC_X] = { .name = "SRC_X", },
   2215         [DRMMODE_PLANE_SRC_Y] = { .name = "SRC_Y", },
   2216         [DRMMODE_PLANE_SRC_W] = { .name = "SRC_W", },
   2217         [DRMMODE_PLANE_SRC_H] = { .name = "SRC_H", },
   2218         [DRMMODE_PLANE_CRTC_X] = { .name = "CRTC_X", },
   2219         [DRMMODE_PLANE_CRTC_Y] = { .name = "CRTC_Y", },
   2220         [DRMMODE_PLANE_CRTC_W] = { .name = "CRTC_W", },
   2221         [DRMMODE_PLANE_CRTC_H] = { .name = "CRTC_H", },
   2222     };
   2223     drmmode_prop_info_rec tmp_props[DRMMODE_PLANE__COUNT];
   2224 
   2225     if (!drmmode_prop_info_copy(tmp_props, plane_props, DRMMODE_PLANE__COUNT, 0)) {
   2226         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
   2227                    "failed to copy plane property info\n");
   2228         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
   2229         return;
   2230     }
   2231 
   2232     kplane_res = drmModeGetPlaneResources(drmmode->fd);
   2233     if (!kplane_res) {
   2234         xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
   2235                    "failed to get plane resources: %s\n", strerror(errno));
   2236         drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
   2237         return;
   2238     }
   2239 
   2240     for (i = 0; i < kplane_res->count_planes; i++) {
   2241         int plane_id;
   2242 
   2243         kplane = drmModeGetPlane(drmmode->fd, kplane_res->planes[i]);
   2244         if (!kplane)
   2245             continue;
   2246 
   2247         if (!(kplane->possible_crtcs & (1 << num)) ||
   2248             is_plane_assigned(drmmode->scrn, kplane->plane_id)) {
   2249             drmModeFreePlane(kplane);
   2250             continue;
   2251         }
   2252 
   2253         plane_id = kplane->plane_id;
   2254 
   2255         props = drmModeObjectGetProperties(drmmode->fd, plane_id,
   2256                                            DRM_MODE_OBJECT_PLANE);
   2257         if (!props) {
   2258             xf86DrvMsg(drmmode->scrn->scrnIndex, X_ERROR,
   2259                     "couldn't get plane properties\n");
   2260             drmModeFreePlane(kplane);
   2261             continue;
   2262         }
   2263 
   2264         drmmode_prop_info_update(drmmode, tmp_props, DRMMODE_PLANE__COUNT, props);
   2265 
   2266         /* Only primary planes are important for atomic page-flipping */
   2267         type = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_TYPE],
   2268                                       props, DRMMODE_PLANE_TYPE__COUNT);
   2269         if (type != DRMMODE_PLANE_TYPE_PRIMARY) {
   2270             drmModeFreePlane(kplane);
   2271             drmModeFreeObjectProperties(props);
   2272             continue;
   2273         }
   2274 
   2275         /* Check if plane is already on this CRTC */
   2276         current_crtc = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_CRTC_ID],
   2277                                               props, 0);
   2278         if (current_crtc == drmmode_crtc->mode_crtc->crtc_id) {
   2279             if (best_plane) {
   2280                 drmModeFreePlane(best_kplane);
   2281                 drmmode_prop_info_free(drmmode_crtc->props_plane, DRMMODE_PLANE__COUNT);
   2282             }
   2283             best_plane = plane_id;
   2284             best_kplane = kplane;
   2285             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
   2286                                              props, 0);
   2287             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
   2288                                    DRMMODE_PLANE__COUNT, 1);
   2289             drmModeFreeObjectProperties(props);
   2290             break;
   2291         }
   2292 
   2293         if (!best_plane) {
   2294             best_plane = plane_id;
   2295             best_kplane = kplane;
   2296             blob_id = drmmode_prop_get_value(&tmp_props[DRMMODE_PLANE_IN_FORMATS],
   2297                                              props, 0);
   2298             drmmode_prop_info_copy(drmmode_crtc->props_plane, tmp_props,
   2299                                    DRMMODE_PLANE__COUNT, 1);
   2300         } else {
   2301             drmModeFreePlane(kplane);
   2302         }
   2303 
   2304         drmModeFreeObjectProperties(props);
   2305     }
   2306 
   2307     drmmode_crtc->plane_id = best_plane;
   2308     if (best_kplane) {
   2309         drmmode_crtc->num_formats = best_kplane->count_formats;
   2310         drmmode_crtc->formats = calloc(sizeof(drmmode_format_rec),
   2311                                        best_kplane->count_formats);
   2312         if (!populate_format_modifiers(crtc, best_kplane, blob_id)) {
   2313             for (i = 0; i < best_kplane->count_formats; i++)
   2314                 drmmode_crtc->formats[i].format = best_kplane->formats[i];
   2315         }
   2316         drmModeFreePlane(best_kplane);
   2317     }
   2318 
   2319     drmmode_prop_info_free(tmp_props, DRMMODE_PLANE__COUNT);
   2320     drmModeFreePlaneResources(kplane_res);
   2321 }
   2322 
   2323 static uint32_t
   2324 drmmode_crtc_get_prop_id(uint32_t drm_fd,
   2325                          drmModeObjectPropertiesPtr props,
   2326                          char const* name)
   2327 {
   2328     uint32_t i, prop_id = 0;
   2329 
   2330     for (i = 0; !prop_id && i < props->count_props; ++i) {
   2331         drmModePropertyPtr drm_prop =
   2332                      drmModeGetProperty(drm_fd, props->props[i]);
   2333 
   2334         if (!drm_prop)
   2335             continue;
   2336 
   2337         if (strcmp(drm_prop->name, name) == 0)
   2338             prop_id = drm_prop->prop_id;
   2339 
   2340         drmModeFreeProperty(drm_prop);
   2341     }
   2342 
   2343     return prop_id;
   2344 }
   2345 
   2346 static void
   2347 drmmode_crtc_vrr_init(int drm_fd, xf86CrtcPtr crtc)
   2348 {
   2349     drmModeObjectPropertiesPtr drm_props;
   2350     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2351     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   2352 
   2353     if (drmmode->vrr_prop_id)
   2354         return;
   2355 
   2356     drm_props = drmModeObjectGetProperties(drm_fd,
   2357                                            drmmode_crtc->mode_crtc->crtc_id,
   2358                                            DRM_MODE_OBJECT_CRTC);
   2359 
   2360     if (!drm_props)
   2361         return;
   2362 
   2363     drmmode->vrr_prop_id = drmmode_crtc_get_prop_id(drm_fd,
   2364                                                     drm_props,
   2365                                                     "VRR_ENABLED");
   2366 
   2367     drmModeFreeObjectProperties(drm_props);
   2368 }
   2369 
   2370 static unsigned int
   2371 drmmode_crtc_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num)
   2372 {
   2373     xf86CrtcPtr crtc;
   2374     drmmode_crtc_private_ptr drmmode_crtc;
   2375     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
   2376     drmModeObjectPropertiesPtr props;
   2377     static const drmmode_prop_info_rec crtc_props[] = {
   2378         [DRMMODE_CRTC_ACTIVE] = { .name = "ACTIVE" },
   2379         [DRMMODE_CRTC_MODE_ID] = { .name = "MODE_ID" },
   2380         [DRMMODE_CRTC_GAMMA_LUT] = { .name = "GAMMA_LUT" },
   2381         [DRMMODE_CRTC_GAMMA_LUT_SIZE] = { .name = "GAMMA_LUT_SIZE" },
   2382         [DRMMODE_CRTC_CTM] = { .name = "CTM" },
   2383     };
   2384 
   2385     crtc = xf86CrtcCreate(pScrn, &drmmode_crtc_funcs);
   2386     if (crtc == NULL)
   2387         return 0;
   2388     drmmode_crtc = xnfcalloc(sizeof(drmmode_crtc_private_rec), 1);
   2389     crtc->driver_private = drmmode_crtc;
   2390     drmmode_crtc->mode_crtc =
   2391         drmModeGetCrtc(drmmode->fd, mode_res->crtcs[num]);
   2392     drmmode_crtc->drmmode = drmmode;
   2393     drmmode_crtc->vblank_pipe = drmmode_crtc_vblank_pipe(num);
   2394     xorg_list_init(&drmmode_crtc->mode_list);
   2395 
   2396     props = drmModeObjectGetProperties(drmmode->fd, mode_res->crtcs[num],
   2397                                        DRM_MODE_OBJECT_CRTC);
   2398     if (!props || !drmmode_prop_info_copy(drmmode_crtc->props, crtc_props,
   2399                                           DRMMODE_CRTC__COUNT, 0)) {
   2400         xf86CrtcDestroy(crtc);
   2401         return 0;
   2402     }
   2403 
   2404     drmmode_prop_info_update(drmmode, drmmode_crtc->props,
   2405                              DRMMODE_CRTC__COUNT, props);
   2406     drmModeFreeObjectProperties(props);
   2407     drmmode_crtc_create_planes(crtc, num);
   2408 
   2409     /* Hide any cursors which may be active from previous users */
   2410     drmModeSetCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, 0, 0, 0);
   2411 
   2412     drmmode_crtc_vrr_init(drmmode->fd, crtc);
   2413 
   2414     /* Mark num'th crtc as in use on this device. */
   2415     ms_ent->assigned_crtcs |= (1 << num);
   2416     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
   2417                    "Allocated crtc nr. %d to this screen.\n", num);
   2418 
   2419     if (drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id &&
   2420         drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value) {
   2421         /*
   2422          * GAMMA_LUT property supported, and so far tested to be safe to use by
   2423          * default for lut sizes up to 4096 slots. Intel Tigerlake+ has some
   2424          * issues, and a large GAMMA_LUT with 262145 slots, so keep GAMMA_LUT
   2425          * off for large lut sizes by default for now.
   2426          */
   2427         drmmode_crtc->use_gamma_lut = drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value <= 4096;
   2428 
   2429         /* Allow config override. */
   2430         drmmode_crtc->use_gamma_lut = xf86ReturnOptValBool(drmmode->Options,
   2431                                                            OPTION_USE_GAMMA_LUT,
   2432                                                            drmmode_crtc->use_gamma_lut);
   2433     } else {
   2434         drmmode_crtc->use_gamma_lut = FALSE;
   2435     }
   2436 
   2437     if (drmmode_crtc->use_gamma_lut &&
   2438         drmmode_crtc->props[DRMMODE_CRTC_CTM].prop_id) {
   2439         drmmode->use_ctm = TRUE;
   2440     }
   2441 
   2442     return 1;
   2443 }
   2444 
   2445 /*
   2446  * Update all of the property values for an output
   2447  */
   2448 static void
   2449 drmmode_output_update_properties(xf86OutputPtr output)
   2450 {
   2451     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2452     int i, j, k;
   2453     int err;
   2454     drmModeConnectorPtr koutput;
   2455 
   2456     /* Use the most recently fetched values from the kernel */
   2457     koutput = drmmode_output->mode_output;
   2458 
   2459     if (!koutput)
   2460         return;
   2461 
   2462     for (i = 0; i < drmmode_output->num_props; i++) {
   2463         drmmode_prop_ptr p = &drmmode_output->props[i];
   2464 
   2465         for (j = 0; koutput && j < koutput->count_props; j++) {
   2466             if (koutput->props[j] == p->mode_prop->prop_id) {
   2467 
   2468                 /* Check to see if the property value has changed */
   2469                 if (koutput->prop_values[j] != p->value) {
   2470 
   2471                     p->value = koutput->prop_values[j];
   2472 
   2473                     if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
   2474                         INT32 value = p->value;
   2475 
   2476                         err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   2477                                                      XA_INTEGER, 32, PropModeReplace, 1,
   2478                                                      &value, FALSE, TRUE);
   2479 
   2480                         if (err != 0) {
   2481                             xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2482                                        "RRChangeOutputProperty error, %d\n", err);
   2483                         }
   2484                     }
   2485                     else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
   2486                         for (k = 0; k < p->mode_prop->count_enums; k++)
   2487                             if (p->mode_prop->enums[k].value == p->value)
   2488                                 break;
   2489                         if (k < p->mode_prop->count_enums) {
   2490                             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   2491                                                          XA_ATOM, 32, PropModeReplace, 1,
   2492                                                          &p->atoms[k + 1], FALSE, TRUE);
   2493                             if (err != 0) {
   2494                                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2495                                            "RRChangeOutputProperty error, %d\n", err);
   2496                             }
   2497                         }
   2498                     }
   2499                 }
   2500                 break;
   2501             }
   2502         }
   2503     }
   2504 
   2505     /* Update the CTM property */
   2506     if (drmmode_output->ctm_atom) {
   2507         err = RRChangeOutputProperty(output->randr_output,
   2508                                      drmmode_output->ctm_atom,
   2509                                      XA_INTEGER, 32, PropModeReplace, 18,
   2510                                      &drmmode_output->ctm,
   2511                                      FALSE, TRUE);
   2512         if (err != 0) {
   2513             xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2514                        "RRChangeOutputProperty error, %d\n", err);
   2515         }
   2516     }
   2517 
   2518 }
   2519 
   2520 static xf86OutputStatus
   2521 drmmode_output_detect(xf86OutputPtr output)
   2522 {
   2523     /* go to the hw and retrieve a new output struct */
   2524     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2525     drmmode_ptr drmmode = drmmode_output->drmmode;
   2526     xf86OutputStatus status;
   2527 
   2528     if (drmmode_output->output_id == -1)
   2529         return XF86OutputStatusDisconnected;
   2530 
   2531     drmModeFreeConnector(drmmode_output->mode_output);
   2532 
   2533     drmmode_output->mode_output =
   2534         drmModeGetConnector(drmmode->fd, drmmode_output->output_id);
   2535 
   2536     if (!drmmode_output->mode_output) {
   2537         drmmode_output->output_id = -1;
   2538         return XF86OutputStatusDisconnected;
   2539     }
   2540 
   2541     drmmode_output_update_properties(output);
   2542 
   2543     switch (drmmode_output->mode_output->connection) {
   2544     case DRM_MODE_CONNECTED:
   2545         status = XF86OutputStatusConnected;
   2546         break;
   2547     case DRM_MODE_DISCONNECTED:
   2548         status = XF86OutputStatusDisconnected;
   2549         break;
   2550     default:
   2551     case DRM_MODE_UNKNOWNCONNECTION:
   2552         status = XF86OutputStatusUnknown;
   2553         break;
   2554     }
   2555     return status;
   2556 }
   2557 
   2558 static Bool
   2559 drmmode_output_mode_valid(xf86OutputPtr output, DisplayModePtr pModes)
   2560 {
   2561     return MODE_OK;
   2562 }
   2563 
   2564 static int
   2565 koutput_get_prop_idx(int fd, drmModeConnectorPtr koutput,
   2566         int type, const char *name)
   2567 {
   2568     int idx = -1;
   2569 
   2570     for (int i = 0; i < koutput->count_props; i++) {
   2571         drmModePropertyPtr prop = drmModeGetProperty(fd, koutput->props[i]);
   2572 
   2573         if (!prop)
   2574             continue;
   2575 
   2576         if (drm_property_type_is(prop, type) && !strcmp(prop->name, name))
   2577             idx = i;
   2578 
   2579         drmModeFreeProperty(prop);
   2580 
   2581         if (idx > -1)
   2582             break;
   2583     }
   2584 
   2585     return idx;
   2586 }
   2587 
   2588 static int
   2589 koutput_get_prop_id(int fd, drmModeConnectorPtr koutput,
   2590         int type, const char *name)
   2591 {
   2592     int idx = koutput_get_prop_idx(fd, koutput, type, name);
   2593 
   2594     return (idx > -1) ? koutput->props[idx] : -1;
   2595 }
   2596 
   2597 static drmModePropertyBlobPtr
   2598 koutput_get_prop_blob(int fd, drmModeConnectorPtr koutput, const char *name)
   2599 {
   2600     drmModePropertyBlobPtr blob = NULL;
   2601     int idx = koutput_get_prop_idx(fd, koutput, DRM_MODE_PROP_BLOB, name);
   2602 
   2603     if (idx > -1)
   2604         blob = drmModeGetPropertyBlob(fd, koutput->prop_values[idx]);
   2605 
   2606     return blob;
   2607 }
   2608 
   2609 static void
   2610 drmmode_output_attach_tile(xf86OutputPtr output)
   2611 {
   2612     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2613     drmModeConnectorPtr koutput = drmmode_output->mode_output;
   2614     drmmode_ptr drmmode = drmmode_output->drmmode;
   2615     struct xf86CrtcTileInfo tile_info, *set = NULL;
   2616 
   2617     if (!koutput) {
   2618         xf86OutputSetTile(output, NULL);
   2619         return;
   2620     }
   2621 
   2622     drmModeFreePropertyBlob(drmmode_output->tile_blob);
   2623 
   2624     /* look for a TILE property */
   2625     drmmode_output->tile_blob =
   2626         koutput_get_prop_blob(drmmode->fd, koutput, "TILE");
   2627 
   2628     if (drmmode_output->tile_blob) {
   2629         if (xf86OutputParseKMSTile(drmmode_output->tile_blob->data, drmmode_output->tile_blob->length, &tile_info) == TRUE)
   2630             set = &tile_info;
   2631     }
   2632     xf86OutputSetTile(output, set);
   2633 }
   2634 
   2635 static Bool
   2636 has_panel_fitter(xf86OutputPtr output)
   2637 {
   2638     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2639     drmModeConnectorPtr koutput = drmmode_output->mode_output;
   2640     drmmode_ptr drmmode = drmmode_output->drmmode;
   2641     int idx;
   2642 
   2643     /* Presume that if the output supports scaling, then we have a
   2644      * panel fitter capable of adjust any mode to suit.
   2645      */
   2646     idx = koutput_get_prop_idx(drmmode->fd, koutput,
   2647             DRM_MODE_PROP_ENUM, "scaling mode");
   2648 
   2649     return (idx > -1);
   2650 }
   2651 
   2652 static DisplayModePtr
   2653 drmmode_output_add_gtf_modes(xf86OutputPtr output, DisplayModePtr Modes)
   2654 {
   2655     xf86MonPtr mon = output->MonInfo;
   2656     DisplayModePtr i, m, preferred = NULL;
   2657     int max_x = 0, max_y = 0;
   2658     float max_vrefresh = 0.0;
   2659 
   2660     if (mon && gtf_supported(mon))
   2661         return Modes;
   2662 
   2663     if (!has_panel_fitter(output))
   2664         return Modes;
   2665 
   2666     for (m = Modes; m; m = m->next) {
   2667         if (m->type & M_T_PREFERRED)
   2668             preferred = m;
   2669         max_x = max(max_x, m->HDisplay);
   2670         max_y = max(max_y, m->VDisplay);
   2671         max_vrefresh = max(max_vrefresh, xf86ModeVRefresh(m));
   2672     }
   2673 
   2674     max_vrefresh = max(max_vrefresh, 60.0);
   2675     max_vrefresh *= (1 + SYNC_TOLERANCE);
   2676 
   2677     m = xf86GetDefaultModes();
   2678     xf86ValidateModesSize(output->scrn, m, max_x, max_y, 0);
   2679 
   2680     for (i = m; i; i = i->next) {
   2681         if (xf86ModeVRefresh(i) > max_vrefresh)
   2682             i->status = MODE_VSYNC;
   2683         if (preferred &&
   2684             i->HDisplay >= preferred->HDisplay &&
   2685             i->VDisplay >= preferred->VDisplay &&
   2686             xf86ModeVRefresh(i) >= xf86ModeVRefresh(preferred))
   2687             i->status = MODE_VSYNC;
   2688     }
   2689 
   2690     xf86PruneInvalidModes(output->scrn, &m, FALSE);
   2691 
   2692     return xf86ModesAdd(Modes, m);
   2693 }
   2694 
   2695 static DisplayModePtr
   2696 drmmode_output_get_modes(xf86OutputPtr output)
   2697 {
   2698     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2699     drmModeConnectorPtr koutput = drmmode_output->mode_output;
   2700     drmmode_ptr drmmode = drmmode_output->drmmode;
   2701     int i;
   2702     DisplayModePtr Modes = NULL, Mode;
   2703     xf86MonPtr mon = NULL;
   2704 
   2705     if (!koutput)
   2706         return NULL;
   2707 
   2708     drmModeFreePropertyBlob(drmmode_output->edid_blob);
   2709 
   2710     /* look for an EDID property */
   2711     drmmode_output->edid_blob =
   2712         koutput_get_prop_blob(drmmode->fd, koutput, "EDID");
   2713 
   2714     if (drmmode_output->edid_blob) {
   2715         mon = xf86InterpretEDID(output->scrn->scrnIndex,
   2716                                 drmmode_output->edid_blob->data);
   2717         if (mon && drmmode_output->edid_blob->length > 128)
   2718             mon->flags |= MONITOR_EDID_COMPLETE_RAWDATA;
   2719     }
   2720     xf86OutputSetEDID(output, mon);
   2721 
   2722     drmmode_output_attach_tile(output);
   2723 
   2724     /* modes should already be available */
   2725     for (i = 0; i < koutput->count_modes; i++) {
   2726         Mode = xnfalloc(sizeof(DisplayModeRec));
   2727 
   2728         drmmode_ConvertFromKMode(output->scrn, &koutput->modes[i], Mode);
   2729         Modes = xf86ModesAdd(Modes, Mode);
   2730 
   2731     }
   2732 
   2733     return drmmode_output_add_gtf_modes(output, Modes);
   2734 }
   2735 
   2736 static void
   2737 drmmode_output_destroy(xf86OutputPtr output)
   2738 {
   2739     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2740     int i;
   2741 
   2742     drmModeFreePropertyBlob(drmmode_output->edid_blob);
   2743     drmModeFreePropertyBlob(drmmode_output->tile_blob);
   2744 
   2745     for (i = 0; i < drmmode_output->num_props; i++) {
   2746         drmModeFreeProperty(drmmode_output->props[i].mode_prop);
   2747         free(drmmode_output->props[i].atoms);
   2748     }
   2749     free(drmmode_output->props);
   2750     if (drmmode_output->mode_output) {
   2751         for (i = 0; i < drmmode_output->mode_output->count_encoders; i++) {
   2752             drmModeFreeEncoder(drmmode_output->mode_encoders[i]);
   2753         }
   2754         drmModeFreeConnector(drmmode_output->mode_output);
   2755     }
   2756     free(drmmode_output->mode_encoders);
   2757     free(drmmode_output);
   2758     output->driver_private = NULL;
   2759 }
   2760 
   2761 static void
   2762 drmmode_output_dpms(xf86OutputPtr output, int mode)
   2763 {
   2764     modesettingPtr ms = modesettingPTR(output->scrn);
   2765     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2766     drmmode_ptr drmmode = drmmode_output->drmmode;
   2767     xf86CrtcPtr crtc = output->crtc;
   2768     drmModeConnectorPtr koutput = drmmode_output->mode_output;
   2769 
   2770     if (!koutput)
   2771         return;
   2772 
   2773     /* XXX Check if DPMS mode is already the right one */
   2774 
   2775     drmmode_output->dpms = mode;
   2776 
   2777     if (ms->atomic_modeset) {
   2778         if (mode != DPMSModeOn && !ms->pending_modeset)
   2779             drmmode_output_disable(output);
   2780     } else {
   2781         drmModeConnectorSetProperty(drmmode->fd, koutput->connector_id,
   2782                                     drmmode_output->dpms_enum_id, mode);
   2783     }
   2784 
   2785     if (crtc) {
   2786         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   2787 
   2788         if (mode == DPMSModeOn) {
   2789             if (drmmode_crtc->need_modeset)
   2790                 drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
   2791                                        crtc->x, crtc->y);
   2792 
   2793             if (drmmode_crtc->enable_flipping)
   2794                 drmmode_InitSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
   2795         } else {
   2796             if (drmmode_crtc->enable_flipping)
   2797                 drmmode_FiniSharedPixmapFlipping(crtc, drmmode_crtc->drmmode);
   2798         }
   2799     }
   2800 
   2801     return;
   2802 }
   2803 
   2804 static Bool
   2805 drmmode_property_ignore(drmModePropertyPtr prop)
   2806 {
   2807     if (!prop)
   2808         return TRUE;
   2809     /* ignore blob prop */
   2810     if (prop->flags & DRM_MODE_PROP_BLOB)
   2811         return TRUE;
   2812     /* ignore standard property */
   2813     if (!strcmp(prop->name, "EDID") || !strcmp(prop->name, "DPMS") ||
   2814         !strcmp(prop->name, "CRTC_ID"))
   2815         return TRUE;
   2816 
   2817     return FALSE;
   2818 }
   2819 
   2820 static void
   2821 drmmode_output_create_resources(xf86OutputPtr output)
   2822 {
   2823     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2824     drmModeConnectorPtr mode_output = drmmode_output->mode_output;
   2825     drmmode_ptr drmmode = drmmode_output->drmmode;
   2826     drmModePropertyPtr drmmode_prop;
   2827     int i, j, err;
   2828 
   2829     drmmode_output->props =
   2830         calloc(mode_output->count_props, sizeof(drmmode_prop_rec));
   2831     if (!drmmode_output->props)
   2832         return;
   2833 
   2834     drmmode_output->num_props = 0;
   2835     for (i = 0, j = 0; i < mode_output->count_props; i++) {
   2836         drmmode_prop = drmModeGetProperty(drmmode->fd, mode_output->props[i]);
   2837         if (drmmode_property_ignore(drmmode_prop)) {
   2838             drmModeFreeProperty(drmmode_prop);
   2839             continue;
   2840         }
   2841         drmmode_output->props[j].mode_prop = drmmode_prop;
   2842         drmmode_output->props[j].value = mode_output->prop_values[i];
   2843         drmmode_output->num_props++;
   2844         j++;
   2845     }
   2846 
   2847     /* Create CONNECTOR_ID property */
   2848     {
   2849         Atom    name = MakeAtom("CONNECTOR_ID", 12, TRUE);
   2850         INT32   value = mode_output->connector_id;
   2851 
   2852         if (name != BAD_RESOURCE) {
   2853             err = RRConfigureOutputProperty(output->randr_output, name,
   2854                                             FALSE, FALSE, TRUE,
   2855                                             1, &value);
   2856             if (err != 0) {
   2857                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2858                            "RRConfigureOutputProperty error, %d\n", err);
   2859             }
   2860             err = RRChangeOutputProperty(output->randr_output, name,
   2861                                          XA_INTEGER, 32, PropModeReplace, 1,
   2862                                          &value, FALSE, FALSE);
   2863             if (err != 0) {
   2864                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2865                            "RRChangeOutputProperty error, %d\n", err);
   2866             }
   2867         }
   2868     }
   2869 
   2870     if (drmmode->use_ctm) {
   2871         Atom name = MakeAtom("CTM", 3, TRUE);
   2872 
   2873         if (name != BAD_RESOURCE) {
   2874             drmmode_output->ctm_atom = name;
   2875 
   2876             err = RRConfigureOutputProperty(output->randr_output, name,
   2877                                             FALSE, FALSE, TRUE, 0, NULL);
   2878             if (err != 0) {
   2879                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2880                            "RRConfigureOutputProperty error, %d\n", err);
   2881             }
   2882 
   2883             err = RRChangeOutputProperty(output->randr_output, name,
   2884                                          XA_INTEGER, 32, PropModeReplace, 18,
   2885                                          &ctm_identity, FALSE, FALSE);
   2886             if (err != 0) {
   2887                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2888                            "RRChangeOutputProperty error, %d\n", err);
   2889             }
   2890 
   2891             drmmode_output->ctm = ctm_identity;
   2892         }
   2893     }
   2894 
   2895     for (i = 0; i < drmmode_output->num_props; i++) {
   2896         drmmode_prop_ptr p = &drmmode_output->props[i];
   2897 
   2898         drmmode_prop = p->mode_prop;
   2899 
   2900         if (drmmode_prop->flags & DRM_MODE_PROP_RANGE) {
   2901             INT32 prop_range[2];
   2902             INT32 value = p->value;
   2903 
   2904             p->num_atoms = 1;
   2905             p->atoms = calloc(p->num_atoms, sizeof(Atom));
   2906             if (!p->atoms)
   2907                 continue;
   2908             p->atoms[0] =
   2909                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
   2910             prop_range[0] = drmmode_prop->values[0];
   2911             prop_range[1] = drmmode_prop->values[1];
   2912             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
   2913                                             FALSE, TRUE,
   2914                                             drmmode_prop->
   2915                                             flags & DRM_MODE_PROP_IMMUTABLE ?
   2916                                             TRUE : FALSE, 2, prop_range);
   2917             if (err != 0) {
   2918                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2919                            "RRConfigureOutputProperty error, %d\n", err);
   2920             }
   2921             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   2922                                          XA_INTEGER, 32, PropModeReplace, 1,
   2923                                          &value, FALSE, TRUE);
   2924             if (err != 0) {
   2925                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2926                            "RRChangeOutputProperty error, %d\n", err);
   2927             }
   2928         }
   2929         else if (drmmode_prop->flags & DRM_MODE_PROP_ENUM) {
   2930             p->num_atoms = drmmode_prop->count_enums + 1;
   2931             p->atoms = calloc(p->num_atoms, sizeof(Atom));
   2932             if (!p->atoms)
   2933                 continue;
   2934             p->atoms[0] =
   2935                 MakeAtom(drmmode_prop->name, strlen(drmmode_prop->name), TRUE);
   2936             for (j = 1; j <= drmmode_prop->count_enums; j++) {
   2937                 struct drm_mode_property_enum *e = &drmmode_prop->enums[j - 1];
   2938 
   2939                 p->atoms[j] = MakeAtom(e->name, strlen(e->name), TRUE);
   2940             }
   2941             err = RRConfigureOutputProperty(output->randr_output, p->atoms[0],
   2942                                             FALSE, FALSE,
   2943                                             drmmode_prop->
   2944                                             flags & DRM_MODE_PROP_IMMUTABLE ?
   2945                                             TRUE : FALSE, p->num_atoms - 1,
   2946                                             (INT32 *) &p->atoms[1]);
   2947             if (err != 0) {
   2948                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2949                            "RRConfigureOutputProperty error, %d\n", err);
   2950             }
   2951             for (j = 0; j < drmmode_prop->count_enums; j++)
   2952                 if (drmmode_prop->enums[j].value == p->value)
   2953                     break;
   2954             /* there's always a matching value */
   2955             err = RRChangeOutputProperty(output->randr_output, p->atoms[0],
   2956                                          XA_ATOM, 32, PropModeReplace, 1,
   2957                                          &p->atoms[j + 1], FALSE, TRUE);
   2958             if (err != 0) {
   2959                 xf86DrvMsg(output->scrn->scrnIndex, X_ERROR,
   2960                            "RRChangeOutputProperty error, %d\n", err);
   2961             }
   2962         }
   2963     }
   2964 }
   2965 
   2966 static Bool
   2967 drmmode_output_set_property(xf86OutputPtr output, Atom property,
   2968                             RRPropertyValuePtr value)
   2969 {
   2970     drmmode_output_private_ptr drmmode_output = output->driver_private;
   2971     drmmode_ptr drmmode = drmmode_output->drmmode;
   2972     int i;
   2973 
   2974     for (i = 0; i < drmmode_output->num_props; i++) {
   2975         drmmode_prop_ptr p = &drmmode_output->props[i];
   2976 
   2977         if (p->atoms[0] != property)
   2978             continue;
   2979 
   2980         if (p->mode_prop->flags & DRM_MODE_PROP_RANGE) {
   2981             uint32_t val;
   2982 
   2983             if (value->type != XA_INTEGER || value->format != 32 ||
   2984                 value->size != 1)
   2985                 return FALSE;
   2986             val = *(uint32_t *) value->data;
   2987 
   2988             drmModeConnectorSetProperty(drmmode->fd, drmmode_output->output_id,
   2989                                         p->mode_prop->prop_id, (uint64_t) val);
   2990             return TRUE;
   2991         }
   2992         else if (p->mode_prop->flags & DRM_MODE_PROP_ENUM) {
   2993             Atom atom;
   2994             const char *name;
   2995             int j;
   2996 
   2997             if (value->type != XA_ATOM || value->format != 32 ||
   2998                 value->size != 1)
   2999                 return FALSE;
   3000             memcpy(&atom, value->data, 4);
   3001             if (!(name = NameForAtom(atom)))
   3002                 return FALSE;
   3003 
   3004             /* search for matching name string, then set its value down */
   3005             for (j = 0; j < p->mode_prop->count_enums; j++) {
   3006                 if (!strcmp(p->mode_prop->enums[j].name, name)) {
   3007                     drmModeConnectorSetProperty(drmmode->fd,
   3008                                                 drmmode_output->output_id,
   3009                                                 p->mode_prop->prop_id,
   3010                                                 p->mode_prop->enums[j].value);
   3011                     return TRUE;
   3012                 }
   3013             }
   3014         }
   3015     }
   3016 
   3017     if (property == drmmode_output->ctm_atom) {
   3018         const size_t matrix_size = sizeof(drmmode_output->ctm);
   3019 
   3020         if (value->type != XA_INTEGER || value->format != 32 ||
   3021             value->size * 4 != matrix_size)
   3022             return FALSE;
   3023 
   3024         memcpy(&drmmode_output->ctm, value->data, matrix_size);
   3025 
   3026         // Update the CRTC if there is one bound to this output.
   3027         if (output->crtc) {
   3028             drmmode_set_ctm(output->crtc, &drmmode_output->ctm);
   3029         }
   3030     }
   3031 
   3032     return TRUE;
   3033 }
   3034 
   3035 static Bool
   3036 drmmode_output_get_property(xf86OutputPtr output, Atom property)
   3037 {
   3038     return TRUE;
   3039 }
   3040 
   3041 static const xf86OutputFuncsRec drmmode_output_funcs = {
   3042     .dpms = drmmode_output_dpms,
   3043     .create_resources = drmmode_output_create_resources,
   3044     .set_property = drmmode_output_set_property,
   3045     .get_property = drmmode_output_get_property,
   3046     .detect = drmmode_output_detect,
   3047     .mode_valid = drmmode_output_mode_valid,
   3048 
   3049     .get_modes = drmmode_output_get_modes,
   3050     .destroy = drmmode_output_destroy
   3051 };
   3052 
   3053 static int subpixel_conv_table[7] = {
   3054     0,
   3055     SubPixelUnknown,
   3056     SubPixelHorizontalRGB,
   3057     SubPixelHorizontalBGR,
   3058     SubPixelVerticalRGB,
   3059     SubPixelVerticalBGR,
   3060     SubPixelNone
   3061 };
   3062 
   3063 static const char *const output_names[] = {
   3064     "None",
   3065     "VGA",
   3066     "DVI-I",
   3067     "DVI-D",
   3068     "DVI-A",
   3069     "Composite",
   3070     "SVIDEO",
   3071     "LVDS",
   3072     "Component",
   3073     "DIN",
   3074     "DP",
   3075     "HDMI",
   3076     "HDMI-B",
   3077     "TV",
   3078     "eDP",
   3079     "Virtual",
   3080     "DSI",
   3081     "DPI",
   3082 };
   3083 
   3084 static xf86OutputPtr find_output(ScrnInfoPtr pScrn, int id)
   3085 {
   3086     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   3087     int i;
   3088     for (i = 0; i < xf86_config->num_output; i++) {
   3089         xf86OutputPtr output = xf86_config->output[i];
   3090         drmmode_output_private_ptr drmmode_output;
   3091 
   3092         drmmode_output = output->driver_private;
   3093         if (drmmode_output->output_id == id)
   3094             return output;
   3095     }
   3096     return NULL;
   3097 }
   3098 
   3099 static int parse_path_blob(drmModePropertyBlobPtr path_blob, int *conn_base_id, char **path)
   3100 {
   3101     char *conn;
   3102     char conn_id[5];
   3103     int id, len;
   3104     char *blob_data;
   3105 
   3106     if (!path_blob)
   3107         return -1;
   3108 
   3109     blob_data = path_blob->data;
   3110     /* we only handle MST paths for now */
   3111     if (strncmp(blob_data, "mst:", 4))
   3112         return -1;
   3113 
   3114     conn = strchr(blob_data + 4, '-');
   3115     if (!conn)
   3116         return -1;
   3117     len = conn - (blob_data + 4);
   3118     if (len + 1 >= sizeof(conn_id))
   3119         return -1;
   3120     memcpy(conn_id, blob_data + 4, len);
   3121     conn_id[len] = '\0';
   3122     id = strtoul(conn_id, NULL, 10);
   3123 
   3124     *conn_base_id = id;
   3125 
   3126     *path = conn + 1;
   3127     return 0;
   3128 }
   3129 
   3130 static void
   3131 drmmode_create_name(ScrnInfoPtr pScrn, drmModeConnectorPtr koutput, char *name,
   3132 		    drmModePropertyBlobPtr path_blob)
   3133 {
   3134     int ret;
   3135     char *extra_path;
   3136     int conn_id;
   3137     xf86OutputPtr output;
   3138 
   3139     ret = parse_path_blob(path_blob, &conn_id, &extra_path);
   3140     if (ret == -1)
   3141         goto fallback;
   3142 
   3143     output = find_output(pScrn, conn_id);
   3144     if (!output)
   3145         goto fallback;
   3146 
   3147     snprintf(name, 32, "%s-%s", output->name, extra_path);
   3148     return;
   3149 
   3150  fallback:
   3151     if (koutput->connector_type >= ARRAY_SIZE(output_names))
   3152         snprintf(name, 32, "Unknown%d-%d", koutput->connector_type, koutput->connector_type_id);
   3153     else if (pScrn->is_gpu)
   3154         snprintf(name, 32, "%s-%d-%d", output_names[koutput->connector_type], pScrn->scrnIndex - GPU_SCREEN_OFFSET + 1, koutput->connector_type_id);
   3155     else
   3156         snprintf(name, 32, "%s-%d", output_names[koutput->connector_type], koutput->connector_type_id);
   3157 }
   3158 
   3159 static Bool
   3160 drmmode_connector_check_vrr_capable(uint32_t drm_fd, int connector_id)
   3161 {
   3162     uint32_t i;
   3163     Bool found = FALSE;
   3164     uint64_t prop_value = 0;
   3165     drmModeObjectPropertiesPtr props;
   3166     const char* prop_name = "VRR_CAPABLE";
   3167 
   3168     props = drmModeObjectGetProperties(drm_fd, connector_id,
   3169                                     DRM_MODE_OBJECT_CONNECTOR);
   3170 
   3171     for (i = 0; !found && i < props->count_props; ++i) {
   3172         drmModePropertyPtr drm_prop = drmModeGetProperty(drm_fd, props->props[i]);
   3173 
   3174         if (!drm_prop)
   3175             continue;
   3176 
   3177         if (strcasecmp(drm_prop->name, prop_name) == 0) {
   3178             prop_value = props->prop_values[i];
   3179             found = TRUE;
   3180         }
   3181 
   3182         drmModeFreeProperty(drm_prop);
   3183     }
   3184 
   3185     drmModeFreeObjectProperties(props);
   3186 
   3187     if(found)
   3188         return prop_value ? TRUE : FALSE;
   3189 
   3190     return FALSE;
   3191 }
   3192 
   3193 static unsigned int
   3194 drmmode_output_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, drmModeResPtr mode_res, int num, Bool dynamic, int crtcshift)
   3195 {
   3196     xf86OutputPtr output;
   3197     xf86CrtcConfigPtr   xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   3198     modesettingPtr ms = modesettingPTR(pScrn);
   3199     drmModeConnectorPtr koutput;
   3200     drmModeEncoderPtr *kencoders = NULL;
   3201     drmmode_output_private_ptr drmmode_output;
   3202     char name[32];
   3203     int i;
   3204     Bool nonDesktop = FALSE;
   3205     drmModePropertyBlobPtr path_blob = NULL;
   3206     const char *s;
   3207     drmModeObjectPropertiesPtr props;
   3208     static const drmmode_prop_info_rec connector_props[] = {
   3209         [DRMMODE_CONNECTOR_CRTC_ID] = { .name = "CRTC_ID", },
   3210     };
   3211 
   3212     koutput =
   3213         drmModeGetConnector(drmmode->fd, mode_res->connectors[num]);
   3214     if (!koutput)
   3215         return 0;
   3216 
   3217     path_blob = koutput_get_prop_blob(drmmode->fd, koutput, "PATH");
   3218     i = koutput_get_prop_idx(drmmode->fd, koutput, DRM_MODE_PROP_RANGE, RR_PROPERTY_NON_DESKTOP);
   3219     if (i >= 0)
   3220         nonDesktop = koutput->prop_values[i] != 0;
   3221 
   3222     drmmode_create_name(pScrn, koutput, name, path_blob);
   3223 
   3224     if (path_blob)
   3225         drmModeFreePropertyBlob(path_blob);
   3226 
   3227     if (path_blob && dynamic) {
   3228         /* see if we have an output with this name already
   3229            and hook stuff up */
   3230         for (i = 0; i < xf86_config->num_output; i++) {
   3231             output = xf86_config->output[i];
   3232 
   3233             if (strncmp(output->name, name, 32))
   3234                 continue;
   3235 
   3236             drmmode_output = output->driver_private;
   3237             drmmode_output->output_id = mode_res->connectors[num];
   3238             drmmode_output->mode_output = koutput;
   3239             output->non_desktop = nonDesktop;
   3240             return 1;
   3241         }
   3242     }
   3243 
   3244     kencoders = calloc(sizeof(drmModeEncoderPtr), koutput->count_encoders);
   3245     if (!kencoders) {
   3246         goto out_free_encoders;
   3247     }
   3248 
   3249     for (i = 0; i < koutput->count_encoders; i++) {
   3250         kencoders[i] = drmModeGetEncoder(drmmode->fd, koutput->encoders[i]);
   3251         if (!kencoders[i]) {
   3252             goto out_free_encoders;
   3253         }
   3254     }
   3255 
   3256     if (xf86IsEntityShared(pScrn->entityList[0])) {
   3257         if ((s = xf86GetOptValString(drmmode->Options, OPTION_ZAPHOD_HEADS))) {
   3258             if (!drmmode_zaphod_string_matches(pScrn, s, name))
   3259                 goto out_free_encoders;
   3260         } else {
   3261             if (!drmmode->is_secondary && (num != 0))
   3262                 goto out_free_encoders;
   3263             else if (drmmode->is_secondary && (num != 1))
   3264                 goto out_free_encoders;
   3265         }
   3266     }
   3267 
   3268     output = xf86OutputCreate(pScrn, &drmmode_output_funcs, name);
   3269     if (!output) {
   3270         goto out_free_encoders;
   3271     }
   3272 
   3273     drmmode_output = calloc(sizeof(drmmode_output_private_rec), 1);
   3274     if (!drmmode_output) {
   3275         xf86OutputDestroy(output);
   3276         goto out_free_encoders;
   3277     }
   3278 
   3279     drmmode_output->output_id = mode_res->connectors[num];
   3280     drmmode_output->mode_output = koutput;
   3281     drmmode_output->mode_encoders = kencoders;
   3282     drmmode_output->drmmode = drmmode;
   3283     output->mm_width = koutput->mmWidth;
   3284     output->mm_height = koutput->mmHeight;
   3285 
   3286     output->subpixel_order = subpixel_conv_table[koutput->subpixel];
   3287     output->interlaceAllowed = TRUE;
   3288     output->doubleScanAllowed = TRUE;
   3289     output->driver_private = drmmode_output;
   3290     output->non_desktop = nonDesktop;
   3291 
   3292     output->possible_crtcs = 0;
   3293     for (i = 0; i < koutput->count_encoders; i++) {
   3294         output->possible_crtcs |= (kencoders[i]->possible_crtcs >> crtcshift) & 0x7f;
   3295     }
   3296     /* work out the possible clones later */
   3297     output->possible_clones = 0;
   3298 
   3299     if (ms->atomic_modeset) {
   3300         if (!drmmode_prop_info_copy(drmmode_output->props_connector,
   3301                                     connector_props, DRMMODE_CONNECTOR__COUNT,
   3302                                     0)) {
   3303             goto out_free_encoders;
   3304         }
   3305         props = drmModeObjectGetProperties(drmmode->fd,
   3306                                            drmmode_output->output_id,
   3307                                            DRM_MODE_OBJECT_CONNECTOR);
   3308         drmmode_prop_info_update(drmmode, drmmode_output->props_connector,
   3309                                  DRMMODE_CONNECTOR__COUNT, props);
   3310     } else {
   3311         drmmode_output->dpms_enum_id =
   3312             koutput_get_prop_id(drmmode->fd, koutput, DRM_MODE_PROP_ENUM,
   3313                                 "DPMS");
   3314     }
   3315 
   3316     if (dynamic) {
   3317         output->randr_output = RROutputCreate(xf86ScrnToScreen(pScrn), output->name, strlen(output->name), output);
   3318         if (output->randr_output) {
   3319             drmmode_output_create_resources(output);
   3320             RRPostPendingProperties(output->randr_output);
   3321         }
   3322     }
   3323 
   3324     ms->is_connector_vrr_capable |=
   3325 	         drmmode_connector_check_vrr_capable(drmmode->fd,
   3326                                                   drmmode_output->output_id);
   3327     return 1;
   3328 
   3329  out_free_encoders:
   3330     if (kencoders) {
   3331         for (i = 0; i < koutput->count_encoders; i++)
   3332             drmModeFreeEncoder(kencoders[i]);
   3333         free(kencoders);
   3334     }
   3335     drmModeFreeConnector(koutput);
   3336 
   3337     return 0;
   3338 }
   3339 
   3340 static uint32_t
   3341 find_clones(ScrnInfoPtr scrn, xf86OutputPtr output)
   3342 {
   3343     drmmode_output_private_ptr drmmode_output =
   3344         output->driver_private, clone_drmout;
   3345     int i;
   3346     xf86OutputPtr clone_output;
   3347     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   3348     int index_mask = 0;
   3349 
   3350     if (drmmode_output->enc_clone_mask == 0)
   3351         return index_mask;
   3352 
   3353     for (i = 0; i < xf86_config->num_output; i++) {
   3354         clone_output = xf86_config->output[i];
   3355         clone_drmout = clone_output->driver_private;
   3356         if (output == clone_output)
   3357             continue;
   3358 
   3359         if (clone_drmout->enc_mask == 0)
   3360             continue;
   3361         if (drmmode_output->enc_clone_mask == clone_drmout->enc_mask)
   3362             index_mask |= (1 << i);
   3363     }
   3364     return index_mask;
   3365 }
   3366 
   3367 static void
   3368 drmmode_clones_init(ScrnInfoPtr scrn, drmmode_ptr drmmode, drmModeResPtr mode_res)
   3369 {
   3370     int i, j;
   3371     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   3372 
   3373     for (i = 0; i < xf86_config->num_output; i++) {
   3374         xf86OutputPtr output = xf86_config->output[i];
   3375         drmmode_output_private_ptr drmmode_output;
   3376 
   3377         drmmode_output = output->driver_private;
   3378         drmmode_output->enc_clone_mask = 0xff;
   3379         /* and all the possible encoder clones for this output together */
   3380         for (j = 0; j < drmmode_output->mode_output->count_encoders; j++) {
   3381             int k;
   3382 
   3383             for (k = 0; k < mode_res->count_encoders; k++) {
   3384                 if (mode_res->encoders[k] ==
   3385                     drmmode_output->mode_encoders[j]->encoder_id)
   3386                     drmmode_output->enc_mask |= (1 << k);
   3387             }
   3388 
   3389             drmmode_output->enc_clone_mask &=
   3390                 drmmode_output->mode_encoders[j]->possible_clones;
   3391         }
   3392     }
   3393 
   3394     for (i = 0; i < xf86_config->num_output; i++) {
   3395         xf86OutputPtr output = xf86_config->output[i];
   3396 
   3397         output->possible_clones = find_clones(scrn, output);
   3398     }
   3399 }
   3400 
   3401 static Bool
   3402 drmmode_set_pixmap_bo(drmmode_ptr drmmode, PixmapPtr pixmap, drmmode_bo *bo)
   3403 {
   3404 #ifdef GLAMOR_HAS_GBM
   3405     ScrnInfoPtr scrn = drmmode->scrn;
   3406     modesettingPtr ms = modesettingPTR(scrn);
   3407 
   3408     if (!drmmode->glamor)
   3409         return TRUE;
   3410 
   3411     if (!ms->glamor.egl_create_textured_pixmap_from_gbm_bo(pixmap, bo->gbm,
   3412                                                            bo->used_modifiers)) {
   3413         xf86DrvMsg(scrn->scrnIndex, X_ERROR, "Failed to create pixmap\n");
   3414         return FALSE;
   3415     }
   3416 #endif
   3417 
   3418     return TRUE;
   3419 }
   3420 
   3421 Bool
   3422 drmmode_glamor_handle_new_screen_pixmap(drmmode_ptr drmmode)
   3423 {
   3424     ScreenPtr screen = xf86ScrnToScreen(drmmode->scrn);
   3425     PixmapPtr screen_pixmap = screen->GetScreenPixmap(screen);
   3426 
   3427     if (!drmmode_set_pixmap_bo(drmmode, screen_pixmap, &drmmode->front_bo))
   3428         return FALSE;
   3429 
   3430     return TRUE;
   3431 }
   3432 
   3433 static Bool
   3434 drmmode_xf86crtc_resize(ScrnInfoPtr scrn, int width, int height)
   3435 {
   3436     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
   3437     modesettingPtr ms = modesettingPTR(scrn);
   3438     drmmode_ptr drmmode = &ms->drmmode;
   3439     drmmode_bo old_front;
   3440     ScreenPtr screen = xf86ScrnToScreen(scrn);
   3441     uint32_t old_fb_id;
   3442     int i, pitch, old_width, old_height, old_pitch;
   3443     int cpp = (scrn->bitsPerPixel + 7) / 8;
   3444     int kcpp = (drmmode->kbpp + 7) / 8;
   3445     PixmapPtr ppix = screen->GetScreenPixmap(screen);
   3446     void *new_pixels = NULL;
   3447 
   3448     if (scrn->virtualX == width && scrn->virtualY == height)
   3449         return TRUE;
   3450 
   3451     xf86DrvMsg(scrn->scrnIndex, X_INFO,
   3452                "Allocate new frame buffer %dx%d stride\n", width, height);
   3453 
   3454     old_width = scrn->virtualX;
   3455     old_height = scrn->virtualY;
   3456     old_pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
   3457     old_front = drmmode->front_bo;
   3458     old_fb_id = drmmode->fb_id;
   3459     drmmode->fb_id = 0;
   3460 
   3461     if (!drmmode_create_bo(drmmode, &drmmode->front_bo,
   3462                            width, height, drmmode->kbpp))
   3463         goto fail;
   3464 
   3465     pitch = drmmode_bo_get_pitch(&drmmode->front_bo);
   3466 
   3467     scrn->virtualX = width;
   3468     scrn->virtualY = height;
   3469     scrn->displayWidth = pitch / kcpp;
   3470 
   3471     if (!drmmode->gbm) {
   3472         new_pixels = drmmode_map_front_bo(drmmode);
   3473         if (!new_pixels)
   3474             goto fail;
   3475     }
   3476 
   3477     if (drmmode->shadow_enable) {
   3478         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
   3479         new_pixels = calloc(1, size);
   3480         if (new_pixels == NULL)
   3481             goto fail;
   3482         free(drmmode->shadow_fb);
   3483         drmmode->shadow_fb = new_pixels;
   3484     }
   3485 
   3486     if (drmmode->shadow_enable2) {
   3487         uint32_t size = scrn->displayWidth * scrn->virtualY * cpp;
   3488         void *fb2 = calloc(1, size);
   3489         free(drmmode->shadow_fb2);
   3490         drmmode->shadow_fb2 = fb2;
   3491     }
   3492 
   3493     screen->ModifyPixmapHeader(ppix, width, height, -1, -1,
   3494                                scrn->displayWidth * cpp, new_pixels);
   3495 
   3496     if (!drmmode_glamor_handle_new_screen_pixmap(drmmode))
   3497         goto fail;
   3498 
   3499     drmmode_clear_pixmap(ppix);
   3500 
   3501     for (i = 0; i < xf86_config->num_crtc; i++) {
   3502         xf86CrtcPtr crtc = xf86_config->crtc[i];
   3503 
   3504         if (!crtc->enabled)
   3505             continue;
   3506 
   3507         drmmode_set_mode_major(crtc, &crtc->mode,
   3508                                crtc->rotation, crtc->x, crtc->y);
   3509     }
   3510 
   3511     if (old_fb_id)
   3512         drmModeRmFB(drmmode->fd, old_fb_id);
   3513 
   3514     drmmode_bo_destroy(drmmode, &old_front);
   3515 
   3516     return TRUE;
   3517 
   3518  fail:
   3519     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
   3520     drmmode->front_bo = old_front;
   3521     scrn->virtualX = old_width;
   3522     scrn->virtualY = old_height;
   3523     scrn->displayWidth = old_pitch / kcpp;
   3524     drmmode->fb_id = old_fb_id;
   3525 
   3526     return FALSE;
   3527 }
   3528 
   3529 static void
   3530 drmmode_validate_leases(ScrnInfoPtr scrn)
   3531 {
   3532     ScreenPtr screen = scrn->pScreen;
   3533     rrScrPrivPtr scr_priv;
   3534     modesettingPtr ms = modesettingPTR(scrn);
   3535     drmmode_ptr drmmode = &ms->drmmode;
   3536     drmModeLesseeListPtr lessees;
   3537     RRLeasePtr lease, next;
   3538     int l;
   3539 
   3540     /* Bail out if RandR wasn't initialized. */
   3541     if (!dixPrivateKeyRegistered(rrPrivKey))
   3542         return;
   3543 
   3544     scr_priv = rrGetScrPriv(screen);
   3545 
   3546     /* We can't talk to the kernel about leases when VT switched */
   3547     if (!scrn->vtSema)
   3548         return;
   3549 
   3550     lessees = drmModeListLessees(drmmode->fd);
   3551     if (!lessees)
   3552         return;
   3553 
   3554     xorg_list_for_each_entry_safe(lease, next, &scr_priv->leases, list) {
   3555         drmmode_lease_private_ptr lease_private = lease->devPrivate;
   3556 
   3557         for (l = 0; l < lessees->count; l++) {
   3558             if (lessees->lessees[l] == lease_private->lessee_id)
   3559                 break;
   3560         }
   3561 
   3562         /* check to see if the lease has gone away */
   3563         if (l == lessees->count) {
   3564             free(lease_private);
   3565             lease->devPrivate = NULL;
   3566             xf86CrtcLeaseTerminated(lease);
   3567         }
   3568     }
   3569 
   3570     free(lessees);
   3571 }
   3572 
   3573 static int
   3574 drmmode_create_lease(RRLeasePtr lease, int *fd)
   3575 {
   3576     ScreenPtr screen = lease->screen;
   3577     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
   3578     modesettingPtr ms = modesettingPTR(scrn);
   3579     drmmode_ptr drmmode = &ms->drmmode;
   3580     int ncrtc = lease->numCrtcs;
   3581     int noutput = lease->numOutputs;
   3582     int nobjects;
   3583     int c, o;
   3584     int i;
   3585     int lease_fd;
   3586     uint32_t *objects;
   3587     drmmode_lease_private_ptr   lease_private;
   3588 
   3589     nobjects = ncrtc + noutput;
   3590 
   3591     if (ms->atomic_modeset)
   3592         nobjects += ncrtc; /* account for planes as well */
   3593 
   3594     if (nobjects == 0)
   3595         return BadValue;
   3596 
   3597     lease_private = calloc(1, sizeof (drmmode_lease_private_rec));
   3598     if (!lease_private)
   3599         return BadAlloc;
   3600 
   3601     objects = xallocarray(nobjects, sizeof (uint32_t));
   3602 
   3603     if (!objects) {
   3604         free(lease_private);
   3605         return BadAlloc;
   3606     }
   3607 
   3608     i = 0;
   3609 
   3610     /* Add CRTC and plane ids */
   3611     for (c = 0; c < ncrtc; c++) {
   3612         xf86CrtcPtr crtc = lease->crtcs[c]->devPrivate;
   3613         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   3614 
   3615         objects[i++] = drmmode_crtc->mode_crtc->crtc_id;
   3616         if (ms->atomic_modeset)
   3617             objects[i++] = drmmode_crtc->plane_id;
   3618     }
   3619 
   3620     /* Add connector ids */
   3621 
   3622     for (o = 0; o < noutput; o++) {
   3623         xf86OutputPtr   output = lease->outputs[o]->devPrivate;
   3624         drmmode_output_private_ptr drmmode_output = output->driver_private;
   3625 
   3626         objects[i++] = drmmode_output->mode_output->connector_id;
   3627     }
   3628 
   3629     /* call kernel to create lease */
   3630     assert (i == nobjects);
   3631 
   3632     lease_fd = drmModeCreateLease(drmmode->fd, objects, nobjects, 0, &lease_private->lessee_id);
   3633 
   3634     free(objects);
   3635 
   3636     if (lease_fd < 0) {
   3637         free(lease_private);
   3638         return BadMatch;
   3639     }
   3640 
   3641     lease->devPrivate = lease_private;
   3642 
   3643     xf86CrtcLeaseStarted(lease);
   3644 
   3645     *fd = lease_fd;
   3646     return Success;
   3647 }
   3648 
   3649 static void
   3650 drmmode_terminate_lease(RRLeasePtr lease)
   3651 {
   3652     ScreenPtr screen = lease->screen;
   3653     ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
   3654     modesettingPtr ms = modesettingPTR(scrn);
   3655     drmmode_ptr drmmode = &ms->drmmode;
   3656     drmmode_lease_private_ptr lease_private = lease->devPrivate;
   3657 
   3658     if (drmModeRevokeLease(drmmode->fd, lease_private->lessee_id) == 0) {
   3659         free(lease_private);
   3660         lease->devPrivate = NULL;
   3661         xf86CrtcLeaseTerminated(lease);
   3662     }
   3663 }
   3664 
   3665 static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = {
   3666     .resize = drmmode_xf86crtc_resize,
   3667     .create_lease = drmmode_create_lease,
   3668     .terminate_lease = drmmode_terminate_lease
   3669 };
   3670 
   3671 Bool
   3672 drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
   3673 {
   3674     modesettingEntPtr ms_ent = ms_ent_priv(pScrn);
   3675     int i;
   3676     int ret;
   3677     uint64_t value = 0;
   3678     unsigned int crtcs_needed = 0;
   3679     drmModeResPtr mode_res;
   3680     int crtcshift;
   3681 
   3682     /* check for dumb capability */
   3683     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_BUFFER, &value);
   3684     if (ret > 0 || value != 1) {
   3685         xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
   3686                    "KMS doesn't support dumb interface\n");
   3687         return FALSE;
   3688     }
   3689 
   3690     xf86CrtcConfigInit(pScrn, &drmmode_xf86crtc_config_funcs);
   3691 
   3692     drmmode->scrn = pScrn;
   3693     drmmode->cpp = cpp;
   3694     mode_res = drmModeGetResources(drmmode->fd);
   3695     if (!mode_res)
   3696         return FALSE;
   3697 
   3698     crtcshift = ffs(ms_ent->assigned_crtcs ^ 0xffffffff) - 1;
   3699     for (i = 0; i < mode_res->count_connectors; i++)
   3700         crtcs_needed += drmmode_output_init(pScrn, drmmode, mode_res, i, FALSE,
   3701                                             crtcshift);
   3702 
   3703     xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
   3704                    "Up to %d crtcs needed for screen.\n", crtcs_needed);
   3705 
   3706     xf86CrtcSetSizeRange(pScrn, 320, 200, mode_res->max_width,
   3707                          mode_res->max_height);
   3708     for (i = 0; i < mode_res->count_crtcs; i++)
   3709         if (!xf86IsEntityShared(pScrn->entityList[0]) ||
   3710             (crtcs_needed && !(ms_ent->assigned_crtcs & (1 << i))))
   3711             crtcs_needed -= drmmode_crtc_init(pScrn, drmmode, mode_res, i);
   3712 
   3713     /* All ZaphodHeads outputs provided with matching crtcs? */
   3714     if (xf86IsEntityShared(pScrn->entityList[0]) && (crtcs_needed > 0))
   3715         xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
   3716                    "%d ZaphodHeads crtcs unavailable. Some outputs will stay off.\n",
   3717                    crtcs_needed);
   3718 
   3719     /* workout clones */
   3720     drmmode_clones_init(pScrn, drmmode, mode_res);
   3721 
   3722     drmModeFreeResources(mode_res);
   3723     xf86ProviderSetup(pScrn, NULL, "modesetting");
   3724 
   3725     xf86InitialConfiguration(pScrn, TRUE);
   3726 
   3727     return TRUE;
   3728 }
   3729 
   3730 Bool
   3731 drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
   3732 {
   3733 #ifdef GLAMOR_HAS_GBM
   3734     ScreenPtr pScreen = xf86ScrnToScreen(pScrn);
   3735     modesettingPtr ms = modesettingPTR(pScrn);
   3736 
   3737     if (drmmode->glamor) {
   3738         if (!ms->glamor.init(pScreen, GLAMOR_USE_EGL_SCREEN)) {
   3739             return FALSE;
   3740         }
   3741 #ifdef GBM_BO_WITH_MODIFIERS
   3742         ms->glamor.set_drawable_modifiers_func(pScreen, get_drawable_modifiers);
   3743 #endif
   3744     }
   3745 #endif
   3746 
   3747     return TRUE;
   3748 }
   3749 
   3750 void
   3751 drmmode_adjust_frame(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int x, int y)
   3752 {
   3753     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
   3754     xf86OutputPtr output = config->output[config->compat_output];
   3755     xf86CrtcPtr crtc = output->crtc;
   3756 
   3757     if (crtc && crtc->enabled) {
   3758         drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation, x, y);
   3759     }
   3760 }
   3761 
   3762 Bool
   3763 drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode, Bool set_hw,
   3764                           Bool ign_err)
   3765 {
   3766     xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn);
   3767     Bool success = TRUE;
   3768     int c;
   3769 
   3770     for (c = 0; c < config->num_crtc; c++) {
   3771         xf86CrtcPtr crtc = config->crtc[c];
   3772         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   3773         xf86OutputPtr output = NULL;
   3774         int o;
   3775 
   3776         /* Skip disabled CRTCs */
   3777         if (!crtc->enabled) {
   3778             if (set_hw) {
   3779                 drmModeSetCrtc(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
   3780                                0, 0, 0, NULL, 0, NULL);
   3781             }
   3782             continue;
   3783         }
   3784 
   3785         if (config->output[config->compat_output]->crtc == crtc)
   3786             output = config->output[config->compat_output];
   3787         else {
   3788             for (o = 0; o < config->num_output; o++)
   3789                 if (config->output[o]->crtc == crtc) {
   3790                     output = config->output[o];
   3791                     break;
   3792                 }
   3793         }
   3794         /* paranoia */
   3795         if (!output)
   3796             continue;
   3797 
   3798         /* Mark that we'll need to re-set the mode for sure */
   3799         memset(&crtc->mode, 0, sizeof(crtc->mode));
   3800         if (!crtc->desiredMode.CrtcHDisplay) {
   3801             DisplayModePtr mode =
   3802                 xf86OutputFindClosestMode(output, pScrn->currentMode);
   3803 
   3804             if (!mode)
   3805                 return FALSE;
   3806             crtc->desiredMode = *mode;
   3807             crtc->desiredRotation = RR_Rotate_0;
   3808             crtc->desiredX = 0;
   3809             crtc->desiredY = 0;
   3810         }
   3811 
   3812         if (set_hw) {
   3813             if (!crtc->funcs->
   3814                 set_mode_major(crtc, &crtc->desiredMode, crtc->desiredRotation,
   3815                                crtc->desiredX, crtc->desiredY)) {
   3816                 if (!ign_err)
   3817                     return FALSE;
   3818                 else {
   3819                     success = FALSE;
   3820                     crtc->enabled = FALSE;
   3821                     xf86DrvMsg(pScrn->scrnIndex, X_WARNING,
   3822                                "Failed to set the desired mode on connector %s\n",
   3823                                output->name);
   3824                 }
   3825             }
   3826         } else {
   3827             crtc->mode = crtc->desiredMode;
   3828             crtc->rotation = crtc->desiredRotation;
   3829             crtc->x = crtc->desiredX;
   3830             crtc->y = crtc->desiredY;
   3831             if (!xf86CrtcRotate(crtc))
   3832                 return FALSE;
   3833         }
   3834     }
   3835 
   3836     /* Validate leases on VT re-entry */
   3837     drmmode_validate_leases(pScrn);
   3838 
   3839     return success;
   3840 }
   3841 
   3842 static void
   3843 drmmode_load_palette(ScrnInfoPtr pScrn, int numColors,
   3844                      int *indices, LOCO * colors, VisualPtr pVisual)
   3845 {
   3846     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   3847     uint16_t lut_r[256], lut_g[256], lut_b[256];
   3848     int index, j, i;
   3849     int c;
   3850 
   3851     for (c = 0; c < xf86_config->num_crtc; c++) {
   3852         xf86CrtcPtr crtc = xf86_config->crtc[c];
   3853         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   3854 
   3855         for (i = 0; i < 256; i++) {
   3856             lut_r[i] = drmmode_crtc->lut_r[i] << 6;
   3857             lut_g[i] = drmmode_crtc->lut_g[i] << 6;
   3858             lut_b[i] = drmmode_crtc->lut_b[i] << 6;
   3859         }
   3860 
   3861         switch (pScrn->depth) {
   3862         case 15:
   3863             for (i = 0; i < numColors; i++) {
   3864                 index = indices[i];
   3865                 for (j = 0; j < 8; j++) {
   3866                     lut_r[index * 8 + j] = colors[index].red << 6;
   3867                     lut_g[index * 8 + j] = colors[index].green << 6;
   3868                     lut_b[index * 8 + j] = colors[index].blue << 6;
   3869                 }
   3870             }
   3871             break;
   3872         case 16:
   3873             for (i = 0; i < numColors; i++) {
   3874                 index = indices[i];
   3875 
   3876                 if (i <= 31) {
   3877                     for (j = 0; j < 8; j++) {
   3878                         lut_r[index * 8 + j] = colors[index].red << 6;
   3879                         lut_b[index * 8 + j] = colors[index].blue << 6;
   3880                     }
   3881                 }
   3882 
   3883                 for (j = 0; j < 4; j++) {
   3884                     lut_g[index * 4 + j] = colors[index].green << 6;
   3885                 }
   3886             }
   3887             break;
   3888         default:
   3889             for (i = 0; i < numColors; i++) {
   3890                 index = indices[i];
   3891                 lut_r[index] = colors[index].red << 6;
   3892                 lut_g[index] = colors[index].green << 6;
   3893                 lut_b[index] = colors[index].blue << 6;
   3894             }
   3895             break;
   3896         }
   3897 
   3898         /* Make the change through RandR */
   3899         if (crtc->randr_crtc)
   3900             RRCrtcGammaSet(crtc->randr_crtc, lut_r, lut_g, lut_b);
   3901         else
   3902             crtc->funcs->gamma_set(crtc, lut_r, lut_g, lut_b, 256);
   3903     }
   3904 }
   3905 
   3906 static Bool
   3907 drmmode_crtc_upgrade_lut(xf86CrtcPtr crtc, int num)
   3908 {
   3909     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   3910     uint64_t size;
   3911 
   3912     if (!drmmode_crtc->use_gamma_lut)
   3913         return TRUE;
   3914 
   3915     assert(drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].prop_id);
   3916 
   3917     size = drmmode_crtc->props[DRMMODE_CRTC_GAMMA_LUT_SIZE].value;
   3918 
   3919     if (size != crtc->gamma_size) {
   3920         ScrnInfoPtr pScrn = crtc->scrn;
   3921         uint16_t *gamma = malloc(3 * size * sizeof(uint16_t));
   3922 
   3923         if (gamma) {
   3924             free(crtc->gamma_red);
   3925 
   3926             crtc->gamma_size = size;
   3927             crtc->gamma_red = gamma;
   3928             crtc->gamma_green = gamma + size;
   3929             crtc->gamma_blue = gamma + size * 2;
   3930 
   3931             xf86DrvMsgVerb(pScrn->scrnIndex, X_INFO, MS_LOGLEVEL_DEBUG,
   3932                            "Gamma ramp set to %" PRIu64 " entries on CRTC %d\n",
   3933                            size, num);
   3934         } else {
   3935             xf86DrvMsg(pScrn->scrnIndex, X_ERROR,
   3936                        "Failed to allocate memory for %" PRIu64 " gamma ramp entries "
   3937                        "on CRTC %d.\n",
   3938                        size, num);
   3939             return FALSE;
   3940         }
   3941     }
   3942 
   3943     return TRUE;
   3944 }
   3945 
   3946 Bool
   3947 drmmode_setup_colormap(ScreenPtr pScreen, ScrnInfoPtr pScrn)
   3948 {
   3949     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   3950     int i;
   3951 
   3952     xf86DrvMsg(pScrn->scrnIndex, X_INFO,
   3953               "Initializing kms color map for depth %d, %d bpc.\n",
   3954               pScrn->depth, pScrn->rgbBits);
   3955     if (!miCreateDefColormap(pScreen))
   3956         return FALSE;
   3957 
   3958     /* If the GAMMA_LUT property is available, replace the server's default
   3959      * gamma ramps with ones of the appropriate size. */
   3960     for (i = 0; i < xf86_config->num_crtc; i++)
   3961         if (!drmmode_crtc_upgrade_lut(xf86_config->crtc[i], i))
   3962             return FALSE;
   3963 
   3964     /* Adapt color map size and depth to color depth of screen. */
   3965     if (!xf86HandleColormaps(pScreen, 1 << pScrn->rgbBits, 10,
   3966                              drmmode_load_palette, NULL,
   3967                              CMAP_PALETTED_TRUECOLOR |
   3968                              CMAP_RELOAD_ON_MODE_SWITCH))
   3969         return FALSE;
   3970     return TRUE;
   3971 }
   3972 
   3973 #define DRM_MODE_LINK_STATUS_GOOD       0
   3974 #define DRM_MODE_LINK_STATUS_BAD        1
   3975 
   3976 void
   3977 drmmode_update_kms_state(drmmode_ptr drmmode)
   3978 {
   3979     ScrnInfoPtr scrn = drmmode->scrn;
   3980     drmModeResPtr mode_res;
   3981     xf86CrtcConfigPtr  config = XF86_CRTC_CONFIG_PTR(scrn);
   3982     int i, j;
   3983     Bool found = FALSE;
   3984     Bool changed = FALSE;
   3985 
   3986     /* Try to re-set the mode on all the connectors with a BAD link-state:
   3987      * This may happen if a link degrades and a new modeset is necessary, using
   3988      * different link-training parameters. If the kernel found that the current
   3989      * mode is not achievable anymore, it should have pruned the mode before
   3990      * sending the hotplug event. Try to re-set the currently-set mode to keep
   3991      * the display alive, this will fail if the mode has been pruned.
   3992      * In any case, we will send randr events for the Desktop Environment to
   3993      * deal with it, if it wants to.
   3994      */
   3995     for (i = 0; i < config->num_output; i++) {
   3996         xf86OutputPtr output = config->output[i];
   3997         drmmode_output_private_ptr drmmode_output = output->driver_private;
   3998 
   3999         drmmode_output_detect(output);
   4000 
   4001         /* Get an updated view of the properties for the current connector and
   4002          * look for the link-status property
   4003          */
   4004         for (j = 0; j < drmmode_output->num_props; j++) {
   4005             drmmode_prop_ptr p = &drmmode_output->props[j];
   4006 
   4007             if (!strcmp(p->mode_prop->name, "link-status")) {
   4008                 if (p->value == DRM_MODE_LINK_STATUS_BAD) {
   4009                     xf86CrtcPtr crtc = output->crtc;
   4010                     if (!crtc)
   4011                         continue;
   4012 
   4013                     /* the connector got a link failure, re-set the current mode */
   4014                     drmmode_set_mode_major(crtc, &crtc->mode, crtc->rotation,
   4015                                            crtc->x, crtc->y);
   4016 
   4017                     xf86DrvMsg(scrn->scrnIndex, X_WARNING,
   4018                                "hotplug event: connector %u's link-state is BAD, "
   4019                                "tried resetting the current mode. You may be left"
   4020                                "with a black screen if this fails...\n",
   4021                                drmmode_output->mode_output->connector_id);
   4022                 }
   4023                 break;
   4024             }
   4025         }
   4026     }
   4027 
   4028     mode_res = drmModeGetResources(drmmode->fd);
   4029     if (!mode_res)
   4030         goto out;
   4031 
   4032     if (mode_res->count_crtcs != config->num_crtc) {
   4033         /* this triggers with Zaphod mode where we don't currently support connector hotplug or MST. */
   4034         goto out_free_res;
   4035     }
   4036 
   4037     /* figure out if we have gotten rid of any connectors
   4038        traverse old output list looking for outputs */
   4039     for (i = 0; i < config->num_output; i++) {
   4040         xf86OutputPtr output = config->output[i];
   4041         drmmode_output_private_ptr drmmode_output;
   4042 
   4043         drmmode_output = output->driver_private;
   4044         found = FALSE;
   4045         for (j = 0; j < mode_res->count_connectors; j++) {
   4046             if (mode_res->connectors[j] == drmmode_output->output_id) {
   4047                 found = TRUE;
   4048                 break;
   4049             }
   4050         }
   4051         if (found)
   4052             continue;
   4053 
   4054         drmModeFreeConnector(drmmode_output->mode_output);
   4055         drmmode_output->mode_output = NULL;
   4056         drmmode_output->output_id = -1;
   4057 
   4058         changed = TRUE;
   4059     }
   4060 
   4061     /* find new output ids we don't have outputs for */
   4062     for (i = 0; i < mode_res->count_connectors; i++) {
   4063         found = FALSE;
   4064 
   4065         for (j = 0; j < config->num_output; j++) {
   4066             xf86OutputPtr output = config->output[j];
   4067             drmmode_output_private_ptr drmmode_output;
   4068 
   4069             drmmode_output = output->driver_private;
   4070             if (mode_res->connectors[i] == drmmode_output->output_id) {
   4071                 found = TRUE;
   4072                 break;
   4073             }
   4074         }
   4075         if (found)
   4076             continue;
   4077 
   4078         changed = TRUE;
   4079         drmmode_output_init(scrn, drmmode, mode_res, i, TRUE, 0);
   4080     }
   4081 
   4082     if (changed) {
   4083         RRSetChanged(xf86ScrnToScreen(scrn));
   4084         RRTellChanged(xf86ScrnToScreen(scrn));
   4085     }
   4086 
   4087 out_free_res:
   4088 
   4089     /* Check to see if a lessee has disappeared */
   4090     drmmode_validate_leases(scrn);
   4091 
   4092     drmModeFreeResources(mode_res);
   4093 out:
   4094     RRGetInfo(xf86ScrnToScreen(scrn), TRUE);
   4095 }
   4096 
   4097 #undef DRM_MODE_LINK_STATUS_BAD
   4098 #undef DRM_MODE_LINK_STATUS_GOOD
   4099 
   4100 #ifdef CONFIG_UDEV_KMS
   4101 
   4102 static void
   4103 drmmode_handle_uevents(int fd, void *closure)
   4104 {
   4105     drmmode_ptr drmmode = closure;
   4106     struct udev_device *dev;
   4107     Bool found = FALSE;
   4108 
   4109     while ((dev = udev_monitor_receive_device(drmmode->uevent_monitor))) {
   4110         udev_device_unref(dev);
   4111         found = TRUE;
   4112     }
   4113     if (!found)
   4114         return;
   4115 
   4116     drmmode_update_kms_state(drmmode);
   4117 }
   4118 
   4119 #endif
   4120 
   4121 void
   4122 drmmode_uevent_init(ScrnInfoPtr scrn, drmmode_ptr drmmode)
   4123 {
   4124 #ifdef CONFIG_UDEV_KMS
   4125     struct udev *u;
   4126     struct udev_monitor *mon;
   4127 
   4128     u = udev_new();
   4129     if (!u)
   4130         return;
   4131     mon = udev_monitor_new_from_netlink(u, "udev");
   4132     if (!mon) {
   4133         udev_unref(u);
   4134         return;
   4135     }
   4136 
   4137     if (udev_monitor_filter_add_match_subsystem_devtype(mon,
   4138                                                         "drm",
   4139                                                         "drm_minor") < 0 ||
   4140         udev_monitor_enable_receiving(mon) < 0) {
   4141         udev_monitor_unref(mon);
   4142         udev_unref(u);
   4143         return;
   4144     }
   4145 
   4146     drmmode->uevent_handler =
   4147         xf86AddGeneralHandler(udev_monitor_get_fd(mon),
   4148                               drmmode_handle_uevents, drmmode);
   4149 
   4150     drmmode->uevent_monitor = mon;
   4151 #endif
   4152 }
   4153 
   4154 void
   4155 drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
   4156 {
   4157 #ifdef CONFIG_UDEV_KMS
   4158     if (drmmode->uevent_handler) {
   4159         struct udev *u = udev_monitor_get_udev(drmmode->uevent_monitor);
   4160 
   4161         xf86RemoveGeneralHandler(drmmode->uevent_handler);
   4162 
   4163         udev_monitor_unref(drmmode->uevent_monitor);
   4164         udev_unref(u);
   4165     }
   4166 #endif
   4167 }
   4168 
   4169 /* create front and cursor BOs */
   4170 Bool
   4171 drmmode_create_initial_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
   4172 {
   4173     modesettingPtr ms = modesettingPTR(pScrn);
   4174     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   4175     int width;
   4176     int height;
   4177     int bpp = ms->drmmode.kbpp;
   4178     int i;
   4179     int cpp = (bpp + 7) / 8;
   4180 
   4181     width = pScrn->virtualX;
   4182     height = pScrn->virtualY;
   4183 
   4184     if (!drmmode_create_bo(drmmode, &drmmode->front_bo, width, height, bpp))
   4185         return FALSE;
   4186     pScrn->displayWidth = drmmode_bo_get_pitch(&drmmode->front_bo) / cpp;
   4187 
   4188     width = ms->cursor_width;
   4189     height = ms->cursor_height;
   4190     bpp = 32;
   4191     for (i = 0; i < xf86_config->num_crtc; i++) {
   4192         xf86CrtcPtr crtc = xf86_config->crtc[i];
   4193         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   4194 
   4195         drmmode_crtc->cursor_bo =
   4196             dumb_bo_create(drmmode->fd, width, height, bpp);
   4197     }
   4198     return TRUE;
   4199 }
   4200 
   4201 void *
   4202 drmmode_map_front_bo(drmmode_ptr drmmode)
   4203 {
   4204     return drmmode_bo_map(drmmode, &drmmode->front_bo);
   4205 }
   4206 
   4207 void *
   4208 drmmode_map_secondary_bo(drmmode_ptr drmmode, msPixmapPrivPtr ppriv)
   4209 {
   4210     int ret;
   4211 
   4212     if (ppriv->backing_bo->ptr)
   4213         return ppriv->backing_bo->ptr;
   4214 
   4215     ret = dumb_bo_map(drmmode->fd, ppriv->backing_bo);
   4216     if (ret)
   4217         return NULL;
   4218 
   4219     return ppriv->backing_bo->ptr;
   4220 }
   4221 
   4222 Bool
   4223 drmmode_map_cursor_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
   4224 {
   4225     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   4226     int i, ret;
   4227 
   4228     for (i = 0; i < xf86_config->num_crtc; i++) {
   4229         xf86CrtcPtr crtc = xf86_config->crtc[i];
   4230         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   4231 
   4232         ret = dumb_bo_map(drmmode->fd, drmmode_crtc->cursor_bo);
   4233         if (ret)
   4234             return FALSE;
   4235     }
   4236     return TRUE;
   4237 }
   4238 
   4239 void
   4240 drmmode_free_bos(ScrnInfoPtr pScrn, drmmode_ptr drmmode)
   4241 {
   4242     xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
   4243     int i;
   4244 
   4245     if (drmmode->fb_id) {
   4246         drmModeRmFB(drmmode->fd, drmmode->fb_id);
   4247         drmmode->fb_id = 0;
   4248     }
   4249 
   4250     drmmode_bo_destroy(drmmode, &drmmode->front_bo);
   4251 
   4252     for (i = 0; i < xf86_config->num_crtc; i++) {
   4253         xf86CrtcPtr crtc = xf86_config->crtc[i];
   4254         drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   4255 
   4256         dumb_bo_destroy(drmmode->fd, drmmode_crtc->cursor_bo);
   4257     }
   4258 }
   4259 
   4260 /* ugly workaround to see if we can create 32bpp */
   4261 void
   4262 drmmode_get_default_bpp(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int *depth,
   4263                         int *bpp)
   4264 {
   4265     drmModeResPtr mode_res;
   4266     uint64_t value;
   4267     struct dumb_bo *bo;
   4268     uint32_t fb_id;
   4269     int ret;
   4270 
   4271     /* 16 is fine */
   4272     ret = drmGetCap(drmmode->fd, DRM_CAP_DUMB_PREFERRED_DEPTH, &value);
   4273     if (!ret && (value == 16 || value == 8)) {
   4274         *depth = value;
   4275         *bpp = value;
   4276         return;
   4277     }
   4278 
   4279     *depth = 24;
   4280     mode_res = drmModeGetResources(drmmode->fd);
   4281     if (!mode_res)
   4282         return;
   4283 
   4284     if (mode_res->min_width == 0)
   4285         mode_res->min_width = 1;
   4286     if (mode_res->min_height == 0)
   4287         mode_res->min_height = 1;
   4288     /*create a bo */
   4289     bo = dumb_bo_create(drmmode->fd, mode_res->min_width, mode_res->min_height,
   4290                         32);
   4291     if (!bo) {
   4292         *bpp = 24;
   4293         goto out;
   4294     }
   4295 
   4296     ret = drmModeAddFB(drmmode->fd, mode_res->min_width, mode_res->min_height,
   4297                        24, 32, bo->pitch, bo->handle, &fb_id);
   4298 
   4299     if (ret) {
   4300         *bpp = 24;
   4301         dumb_bo_destroy(drmmode->fd, bo);
   4302         goto out;
   4303     }
   4304 
   4305     drmModeRmFB(drmmode->fd, fb_id);
   4306     *bpp = 32;
   4307 
   4308     dumb_bo_destroy(drmmode->fd, bo);
   4309  out:
   4310     drmModeFreeResources(mode_res);
   4311     return;
   4312 }
   4313 
   4314 void
   4315 drmmode_crtc_set_vrr(xf86CrtcPtr crtc, Bool enabled)
   4316 {
   4317     ScrnInfoPtr pScrn = crtc->scrn;
   4318     modesettingPtr ms = modesettingPTR(pScrn);
   4319     drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
   4320     drmmode_ptr drmmode = drmmode_crtc->drmmode;
   4321 
   4322     if (drmmode->vrr_prop_id && drmmode_crtc->vrr_enabled != enabled &&
   4323         drmModeObjectSetProperty(ms->fd,
   4324                                  drmmode_crtc->mode_crtc->crtc_id,
   4325                                  DRM_MODE_OBJECT_CRTC,
   4326                                  drmmode->vrr_prop_id,
   4327                                  enabled) == 0)
   4328         drmmode_crtc->vrr_enabled = enabled;
   4329 }
   4330 
   4331 /*
   4332  * We hook the screen's cursor-sprite (swcursor) functions to see if a swcursor
   4333  * is active. When a swcursor is active we disable page-flipping.
   4334  */
   4335 
   4336 static void drmmode_sprite_do_set_cursor(msSpritePrivPtr sprite_priv,
   4337                                          ScrnInfoPtr scrn, int x, int y)
   4338 {
   4339     modesettingPtr ms = modesettingPTR(scrn);
   4340     CursorPtr cursor = sprite_priv->cursor;
   4341     Bool sprite_visible = sprite_priv->sprite_visible;
   4342 
   4343     if (cursor) {
   4344         x -= cursor->bits->xhot;
   4345         y -= cursor->bits->yhot;
   4346 
   4347         sprite_priv->sprite_visible =
   4348             x < scrn->virtualX && y < scrn->virtualY &&
   4349             (x + cursor->bits->width > 0) &&
   4350             (y + cursor->bits->height > 0);
   4351     } else {
   4352         sprite_priv->sprite_visible = FALSE;
   4353     }
   4354 
   4355     ms->drmmode.sprites_visible += sprite_priv->sprite_visible - sprite_visible;
   4356 }
   4357 
   4358 static void drmmode_sprite_set_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
   4359                                       CursorPtr pCursor, int x, int y)
   4360 {
   4361     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   4362     modesettingPtr ms = modesettingPTR(scrn);
   4363     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
   4364 
   4365     sprite_priv->cursor = pCursor;
   4366     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
   4367 
   4368     ms->SpriteFuncs->SetCursor(pDev, pScreen, pCursor, x, y);
   4369 }
   4370 
   4371 static void drmmode_sprite_move_cursor(DeviceIntPtr pDev, ScreenPtr pScreen,
   4372                                        int x, int y)
   4373 {
   4374     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   4375     modesettingPtr ms = modesettingPTR(scrn);
   4376     msSpritePrivPtr sprite_priv = msGetSpritePriv(pDev, ms, pScreen);
   4377 
   4378     drmmode_sprite_do_set_cursor(sprite_priv, scrn, x, y);
   4379 
   4380     ms->SpriteFuncs->MoveCursor(pDev, pScreen, x, y);
   4381 }
   4382 
   4383 static Bool drmmode_sprite_realize_realize_cursor(DeviceIntPtr pDev,
   4384                                                   ScreenPtr pScreen,
   4385                                                   CursorPtr pCursor)
   4386 {
   4387     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   4388     modesettingPtr ms = modesettingPTR(scrn);
   4389 
   4390     return ms->SpriteFuncs->RealizeCursor(pDev, pScreen, pCursor);
   4391 }
   4392 
   4393 static Bool drmmode_sprite_realize_unrealize_cursor(DeviceIntPtr pDev,
   4394                                                     ScreenPtr pScreen,
   4395                                                     CursorPtr pCursor)
   4396 {
   4397     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   4398     modesettingPtr ms = modesettingPTR(scrn);
   4399 
   4400     return ms->SpriteFuncs->UnrealizeCursor(pDev, pScreen, pCursor);
   4401 }
   4402 
   4403 static Bool drmmode_sprite_device_cursor_initialize(DeviceIntPtr pDev,
   4404                                                     ScreenPtr pScreen)
   4405 {
   4406     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   4407     modesettingPtr ms = modesettingPTR(scrn);
   4408 
   4409     return ms->SpriteFuncs->DeviceCursorInitialize(pDev, pScreen);
   4410 }
   4411 
   4412 static void drmmode_sprite_device_cursor_cleanup(DeviceIntPtr pDev,
   4413                                                  ScreenPtr pScreen)
   4414 {
   4415     ScrnInfoPtr scrn = xf86ScreenToScrn(pScreen);
   4416     modesettingPtr ms = modesettingPTR(scrn);
   4417 
   4418     ms->SpriteFuncs->DeviceCursorCleanup(pDev, pScreen);
   4419 }
   4420 
   4421 miPointerSpriteFuncRec drmmode_sprite_funcs = {
   4422     .RealizeCursor = drmmode_sprite_realize_realize_cursor,
   4423     .UnrealizeCursor = drmmode_sprite_realize_unrealize_cursor,
   4424     .SetCursor = drmmode_sprite_set_cursor,
   4425     .MoveCursor = drmmode_sprite_move_cursor,
   4426     .DeviceCursorInitialize = drmmode_sprite_device_cursor_initialize,
   4427     .DeviceCursorCleanup = drmmode_sprite_device_cursor_cleanup,
   4428 };
   4429