diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 47857df7..7ff8c7f5 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -1,4 +1,4 @@ -#define _POSIX_C_SOURCE 200112L +#define _XOPEN_SOURCE 700 #include #include #include @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -72,11 +73,86 @@ bool check_drm_features(struct wlr_drm_backend *drm) { return true; } -static int cmp_plane(const void *arg1, const void *arg2) { - const struct wlr_drm_plane *a = arg1; - const struct wlr_drm_plane *b = arg2; +static bool add_plane(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc, drmModePlane *drm_plane, + uint32_t type, union wlr_drm_plane_props *props) { + assert(!(type == DRM_PLANE_TYPE_PRIMARY && crtc->primary)); - return (int)a->type - (int)b->type; + if (type == DRM_PLANE_TYPE_CURSOR && crtc->cursor) { + return true; + } + + struct wlr_drm_plane *p = calloc(1, sizeof(*p)); + if (!p) { + wlr_log_errno(WLR_ERROR, "Allocation failed"); + return false; + } + + p->type = type; + p->id = drm_plane->plane_id; + p->props = *props; + + // Choose an RGB format for the plane + uint32_t rgb_format = DRM_FORMAT_INVALID; + for (size_t j = 0; j < drm_plane->count_formats; ++j) { + uint32_t fmt = drm_plane->formats[j]; + wlr_drm_format_set_add(&p->formats, fmt, DRM_FORMAT_MOD_INVALID); + + if (fmt == DRM_FORMAT_ARGB8888) { + // Prefer formats with alpha channel + rgb_format = fmt; + break; + } else if (fmt == DRM_FORMAT_XRGB8888) { + rgb_format = fmt; + } + } + p->drm_format = rgb_format; + + if (p->props.in_formats) { + uint64_t blob_id; + if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) { + wlr_log(WLR_ERROR, "Failed to read IN_FORMATS property"); + goto error; + } + + drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(drm->fd, blob_id); + if (!blob) { + wlr_log(WLR_ERROR, "Failed to read IN_FORMATS blob"); + goto error; + } + + struct drm_format_modifier_blob *data = blob->data; + uint32_t *fmts = (uint32_t *)((char *)data + data->formats_offset); + struct drm_format_modifier *mods = (struct drm_format_modifier *) + ((char *)data + data->modifiers_offset); + for (uint32_t i = 0; i < data->count_modifiers; ++i) { + for (int j = 0; j < 64; ++j) { + if (mods[i].formats & ((uint64_t)1 << j)) { + wlr_drm_format_set_add(&p->formats, + fmts[j + mods[i].offset], mods[i].modifier); + } + } + } + + drmModeFreePropertyBlob(blob); + } + + switch (type) { + case DRM_PLANE_TYPE_PRIMARY: + crtc->primary = p; + break; + case DRM_PLANE_TYPE_CURSOR: + crtc->cursor = p; + break; + default: + abort(); + } + + return true; + +error: + free(p); + return false; } static bool init_planes(struct wlr_drm_backend *drm) { @@ -88,118 +164,72 @@ static bool init_planes(struct wlr_drm_backend *drm) { wlr_log(WLR_INFO, "Found %"PRIu32" DRM planes", plane_res->count_planes); - if (plane_res->count_planes == 0) { - drmModeFreePlaneResources(plane_res); - return true; - } + for (uint32_t i = 0; i < plane_res->count_planes; ++i) { + uint32_t id = plane_res->planes[i]; - drm->num_planes = plane_res->count_planes; - drm->planes = calloc(drm->num_planes, sizeof(*drm->planes)); - if (!drm->planes) { - wlr_log_errno(WLR_ERROR, "Allocation failed"); - goto error_res; - } - - for (size_t i = 0; i < drm->num_planes; ++i) { - struct wlr_drm_plane *p = &drm->planes[i]; - - drmModePlane *plane = drmModeGetPlane(drm->fd, plane_res->planes[i]); + drmModePlane *plane = drmModeGetPlane(drm->fd, id); if (!plane) { wlr_log_errno(WLR_ERROR, "Failed to get DRM plane"); - goto error_planes; + goto error; } - p->id = plane->plane_id; - p->possible_crtcs = plane->possible_crtcs; + union wlr_drm_plane_props props = {0}; + if (!get_drm_plane_props(drm->fd, id, &props)) { + drmModeFreePlane(plane); + goto error; + } uint64_t type; - if (!get_drm_plane_props(drm->fd, p->id, &p->props) || - !get_drm_prop(drm->fd, p->id, p->props.type, &type)) { + if (!get_drm_prop(drm->fd, id, props.type, &type)) { drmModeFreePlane(plane); - goto error_planes; + goto error; } - p->type = type; - drm->num_type_planes[type]++; + /* + * This is a very naive implementation of the plane matching + * logic. Primary and cursor planes should only work on a + * single CRTC, and this should be perfectly adequate, but + * overlay planes can potentially work with multiple CRTCs, + * meaning this could return inefficent/skewed results. + * + * However, we don't really care about overlay planes, as we + * don't support them yet. We only bother to keep basic + * tracking of them for DRM lease clients. + * + * possible_crtcs is a bitmask of crtcs, where each bit is an + * index into drmModeRes.crtcs. So if bit 0 is set (ffs starts + * counting from 1), crtc 0 is possible. + */ + int crtc_bit = ffs(plane->possible_crtcs) - 1; - // Choose an RGB format for the plane - uint32_t rgb_format = DRM_FORMAT_INVALID; - for (size_t j = 0; j < plane->count_formats; ++j) { - uint32_t fmt = plane->formats[j]; - wlr_drm_format_set_add(&p->formats, fmt, DRM_FORMAT_MOD_INVALID); + // This would be a kernel bug + assert(crtc_bit >= 0 && (size_t)crtc_bit < drm->num_crtcs); - if (fmt == DRM_FORMAT_ARGB8888) { - // Prefer formats with alpha channel - rgb_format = fmt; - break; - } else if (fmt == DRM_FORMAT_XRGB8888) { - rgb_format = fmt; + struct wlr_drm_crtc *crtc = &drm->crtcs[crtc_bit]; + + if (type == DRM_PLANE_TYPE_OVERLAY) { + uint32_t *tmp = realloc(crtc->overlays, + sizeof(*crtc->overlays) * (crtc->num_overlays + 1)); + if (tmp) { + crtc->overlays = tmp; + crtc->overlays[crtc->num_overlays++] = id; } - } - // Some overlays exist which don't support XRGB8888/ARGB8888 - // We aren't even using overlay planes currently, so don't fail - // on something unnecessary. - if (type != DRM_PLANE_TYPE_OVERLAY && rgb_format == DRM_FORMAT_INVALID) { - wlr_log(WLR_ERROR, "Failed to find an RGB format for plane %zu", i); drmModeFreePlane(plane); - goto error_planes; + continue; } - p->drm_format = rgb_format; - if (p->props.in_formats) { - uint64_t blob_id; - if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) { - wlr_log(WLR_ERROR, "Failed to read IN_FORMATS property"); - drmModeFreePlane(plane); - goto error_planes; - } - - drmModePropertyBlobRes *blob = - drmModeGetPropertyBlob(drm->fd, blob_id); - if (!blob) { - wlr_log(WLR_ERROR, "Failed to read IN_FORMATS blob"); - drmModeFreePlane(plane); - goto error_planes; - } - - struct drm_format_modifier_blob *data = blob->data; - uint32_t *fmts = (uint32_t *)((char *)data + data->formats_offset); - struct drm_format_modifier *mods = (struct drm_format_modifier *) - ((char *)data + data->modifiers_offset); - for (uint32_t i = 0; i < data->count_modifiers; ++i) { - for (int j = 0; j < 64; ++j) { - if (mods[i].formats & ((uint64_t)1 << j)) { - wlr_drm_format_set_add(&p->formats, - fmts[j + mods[i].offset], mods[i].modifier); - } - } - } - - drmModeFreePropertyBlob(blob); + if (!add_plane(drm, crtc, plane, type, &props)) { + drmModeFreePlane(plane); + goto error; } drmModeFreePlane(plane); } - wlr_log(WLR_INFO, "(%zu overlay, %zu primary, %zu cursor)", - drm->num_overlay_planes, - drm->num_primary_planes, - drm->num_cursor_planes); - - qsort(drm->planes, drm->num_planes, sizeof(*drm->planes), cmp_plane); - - drm->overlay_planes = drm->planes; - drm->primary_planes = drm->overlay_planes - + drm->num_overlay_planes; - drm->cursor_planes = drm->primary_planes - + drm->num_primary_planes; - drmModeFreePlaneResources(plane_res); return true; -error_planes: - free(drm->planes); -error_res: +error: drmModeFreePlaneResources(plane_res); return false; } @@ -252,26 +282,33 @@ void finish_drm_resources(struct wlr_drm_backend *drm) { return; } - for (size_t i = 0; i < drm->num_planes; ++i) { - struct wlr_drm_plane *p = &drm->planes[i]; - wlr_drm_format_set_finish(&p->formats); - } - for (size_t i = 0; i < drm->num_crtcs; ++i) { struct wlr_drm_crtc *crtc = &drm->crtcs[i]; + drmModeAtomicFree(crtc->atomic); drmModeFreeCrtc(crtc->legacy_crtc); + if (crtc->mode_id) { drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } if (crtc->gamma_lut) { drmModeDestroyPropertyBlob(drm->fd, crtc->gamma_lut); } + free(crtc->gamma_table); + + if (crtc->primary) { + wlr_drm_format_set_finish(&crtc->primary->formats); + free(crtc->primary); + } + if (crtc->cursor) { + wlr_drm_format_set_finish(&crtc->cursor->formats); + free(crtc->cursor); + } + free(crtc->overlays); } free(drm->crtcs); - free(drm->planes); } static struct wlr_drm_connector *get_drm_connector_from_output( @@ -477,7 +514,7 @@ static void drm_connector_start_renderer(struct wlr_drm_connector *conn) { } } -static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs); +static void realloc_crtcs(struct wlr_drm_backend *drm); static void attempt_enable_needs_modeset(struct wlr_drm_backend *drm) { // Try to modeset any output that has a desired mode and a CRTC (ie. was @@ -506,7 +543,7 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) { if (enable && conn->crtc == NULL) { // Maybe we can steal a CRTC from a disabled output - realloc_crtcs(drm, NULL); + realloc_crtcs(drm); } bool ok = drm->iface->conn_enable(drm, conn, enable); @@ -517,7 +554,7 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) { if (enable) { drm_connector_start_renderer(conn); } else { - realloc_crtcs(drm, NULL); + realloc_crtcs(drm); attempt_enable_needs_modeset(drm); } @@ -526,82 +563,6 @@ bool enable_drm_connector(struct wlr_output *output, bool enable) { return true; } -static ssize_t connector_index_from_crtc(struct wlr_drm_backend *drm, - struct wlr_drm_crtc *crtc) { - size_t i = 0; - struct wlr_drm_connector *conn; - wl_list_for_each(conn, &drm->outputs, link) { - if (conn->crtc == crtc) { - return i; - } - ++i; - } - return -1; -} - -static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in, - bool *changed_outputs) { - wlr_log(WLR_DEBUG, "Reallocating planes"); - - // overlay, primary, cursor - for (size_t type = 0; type < 3; ++type) { - if (drm->num_type_planes[type] == 0) { - continue; - } - - uint32_t possible[drm->num_type_planes[type] + 1]; - uint32_t crtc[drm->num_crtcs + 1]; - uint32_t crtc_res[drm->num_crtcs + 1]; - - for (size_t i = 0; i < drm->num_type_planes[type]; ++i) { - possible[i] = drm->type_planes[type][i].possible_crtcs; - } - - for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (crtc_in[i] == UNMATCHED) { - crtc[i] = SKIP; - } else if (drm->crtcs[i].planes[type]) { - crtc[i] = drm->crtcs[i].planes[type] - - drm->type_planes[type]; - } else { - crtc[i] = UNMATCHED; - } - } - - match_obj(drm->num_type_planes[type], possible, - drm->num_crtcs, crtc, crtc_res); - - for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (crtc_res[i] == UNMATCHED || crtc_res[i] == SKIP) { - continue; - } - - struct wlr_drm_crtc *c = &drm->crtcs[i]; - struct wlr_drm_plane **old = &c->planes[type]; - struct wlr_drm_plane *new = &drm->type_planes[type][crtc_res[i]]; - - if (*old != new) { - wlr_log(WLR_DEBUG, - "Assigning plane %d -> %d (type %zu) to CRTC %d", - *old ? (int)(*old)->id : -1, - new ? (int)new->id : -1, - type, - c->id); - - ssize_t conn_idx = connector_index_from_crtc(drm, c); - if (conn_idx >= 0) { - changed_outputs[conn_idx] = true; - } - if (*old) { - finish_drm_surface(&(*old)->surf); - } - finish_drm_surface(&new->surf); - *old = new; - } - } - } -} - static void drm_connector_cleanup(struct wlr_drm_connector *conn); bool drm_connector_set_mode(struct wlr_output *output, @@ -610,7 +571,7 @@ bool drm_connector_set_mode(struct wlr_output *output, struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend); if (conn->crtc == NULL) { // Maybe we can steal a CRTC from a disabled output - realloc_crtcs(drm, NULL); + realloc_crtcs(drm); } if (conn->crtc == NULL) { wlr_log(WLR_ERROR, "Cannot modeset '%s': no CRTC for this connector", @@ -1001,51 +962,37 @@ static void dealloc_crtc(struct wlr_drm_connector *conn) { conn->crtc - drm->crtcs, conn->output.name); set_drm_connector_gamma(&conn->output, 0, NULL, NULL, NULL); - - for (size_t type = 0; type < 3; ++type) { - struct wlr_drm_plane *plane = conn->crtc->planes[type]; - if (plane == NULL) { - continue; - } - - finish_drm_surface(&plane->surf); - conn->crtc->planes[type] = NULL; - } + finish_drm_surface(&conn->crtc->primary->surf); + finish_drm_surface(&conn->crtc->cursor->surf); drm->iface->conn_enable(drm, conn, false); conn->crtc = NULL; } -static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { - size_t num_outputs = wl_list_length(&drm->outputs); - bool changed_local = changed_outputs ? false : true; +static void realloc_crtcs(struct wlr_drm_backend *drm) { + assert(drm->num_crtcs > 0); - if (changed_local) { - changed_outputs = calloc(num_outputs, sizeof(bool)); - if (changed_outputs == NULL) { - wlr_log(WLR_ERROR, "Allocation failed"); - return; - } + size_t num_outputs = wl_list_length(&drm->outputs); + if (num_outputs == 0) { + return; } wlr_log(WLR_DEBUG, "Reallocating CRTCs"); - uint32_t crtc[drm->num_crtcs + 1]; + struct wlr_drm_connector *connectors[num_outputs]; + uint32_t connector_constraints[num_outputs]; + uint32_t previous_match[drm->num_crtcs]; + uint32_t new_match[drm->num_crtcs]; + for (size_t i = 0; i < drm->num_crtcs; ++i) { - crtc[i] = UNMATCHED; + previous_match[i] = UNMATCHED; } - struct wlr_drm_connector *connectors[num_outputs + 1]; - - uint32_t possible_crtc[num_outputs + 1]; - memset(possible_crtc, 0, sizeof(possible_crtc)); - wlr_log(WLR_DEBUG, "State before reallocation:"); - ssize_t i = -1; + size_t i = 0; struct wlr_drm_connector *conn; wl_list_for_each(conn, &drm->outputs, link) { - i++; connectors[i] = conn; wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d desired_enabled=%d", @@ -1054,7 +1001,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { conn->state, conn->desired_enabled); if (conn->crtc) { - crtc[conn->crtc - drm->crtcs] = i; + previous_match[conn->crtc - drm->crtcs] = i; } // Only search CRTCs for user-enabled outputs (that are already @@ -1062,86 +1009,84 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { if ((conn->state == WLR_DRM_CONN_CONNECTED || conn->state == WLR_DRM_CONN_NEEDS_MODESET) && conn->desired_enabled) { - possible_crtc[i] = conn->possible_crtc; + connector_constraints[i] = conn->possible_crtc; + } else { + // Will always fail to match anything + connector_constraints[i] = 0; } + + ++i; } - uint32_t crtc_res[drm->num_crtcs + 1]; - match_obj(wl_list_length(&drm->outputs), possible_crtc, - drm->num_crtcs, crtc, crtc_res); + match_obj(num_outputs, connector_constraints, + drm->num_crtcs, previous_match, new_match); - bool matched[num_outputs + 1]; - memset(matched, false, sizeof(matched)); + // Converts our crtc=>connector result into a connector=>crtc one. + ssize_t connector_match[num_outputs]; + for (size_t i = 0 ; i < num_outputs; ++i) { + connector_match[i] = -1; + } for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (crtc_res[i] != UNMATCHED) { - matched[crtc_res[i]] = true; + if (new_match[i] != UNMATCHED) { + connector_match[new_match[i]] = i; } } - for (size_t i = 0; i < drm->num_crtcs; ++i) { - // We don't want any of the current monitors to be deactivated - if (crtc[i] != UNMATCHED && !matched[crtc[i]] && - connectors[crtc[i]]->desired_enabled) { - wlr_log(WLR_DEBUG, "Could not match a CRTC for connected output %d", - crtc[i]); - goto free_changed_outputs; + /* + * In the case that we add a new connector (hotplug) and we fail to + * match everything, we prefer to fail the new connector and keep all + * of the old mappings instead. + */ + for (size_t i = 0; i < num_outputs; ++i) { + struct wlr_drm_connector *conn = connectors[i]; + if (conn->state == WLR_DRM_CONN_CONNECTED && + conn->desired_enabled && + connector_match[i] == -1) { + wlr_log(WLR_DEBUG, "Could not match a CRTC for previously connected output; " + "keeping old configuration"); + return; } } - - for (size_t i = 0; i < drm->num_crtcs; ++i) { - if (crtc_res[i] == crtc[i]) { - continue; - } - - // De-allocate this CRTC on previous output - if (crtc[i] != UNMATCHED) { - changed_outputs[crtc[i]] = true; - dealloc_crtc(connectors[crtc[i]]); - } - - // Assign this CRTC to next output - if (crtc_res[i] != UNMATCHED) { - changed_outputs[crtc_res[i]] = true; - - struct wlr_drm_connector *conn = connectors[crtc_res[i]]; - dealloc_crtc(conn); - conn->crtc = &drm->crtcs[i]; - - wlr_log(WLR_DEBUG, "Assigning CRTC %zu to output %d -> %d '%s'", - i, crtc[i], crtc_res[i], conn->output.name); - } - } - wlr_log(WLR_DEBUG, "State after reallocation:"); - wl_list_for_each(conn, &drm->outputs, link) { - wlr_log(WLR_DEBUG, " '%s' crtc=%d state=%d desired_enabled=%d", + + // Apply new configuration + for (size_t i = 0; i < num_outputs; ++i) { + struct wlr_drm_connector *conn = connectors[i]; + bool prev_enabled = conn->crtc; + + wlr_log(WLR_DEBUG, " '%s' crtc=%zd state=%d desired_enabled=%d", conn->output.name, - conn->crtc ? (int)(conn->crtc - drm->crtcs) : -1, + connector_match[i], conn->state, conn->desired_enabled); - } - realloc_planes(drm, crtc_res, changed_outputs); + // We don't need to change anything. + if (prev_enabled && connector_match[i] == conn->crtc - drm->crtcs) { + continue; + } + + dealloc_crtc(conn); + + if (connector_match[i] == -1) { + if (prev_enabled) { + wlr_log(WLR_DEBUG, "Output has %s lost its CRTC", + conn->output.name); + conn->state = WLR_DRM_CONN_NEEDS_MODESET; + wlr_output_update_enabled(&conn->output, false); + conn->desired_mode = conn->output.current_mode; + wlr_output_update_mode(&conn->output, NULL); + } + continue; + } + + conn->crtc = &drm->crtcs[connector_match[i]]; + + // Only realloc buffers if we have actually been modeset + if (conn->state != WLR_DRM_CONN_CONNECTED) { + continue; + } - // We need to reinitialize any plane that has changed - i = -1; - wl_list_for_each(conn, &drm->outputs, link) { - i++; struct wlr_output_mode *mode = conn->output.current_mode; - if (conn->state != WLR_DRM_CONN_CONNECTED || !changed_outputs[i]) { - continue; - } - - if (conn->crtc == NULL) { - wlr_log(WLR_DEBUG, "Output has %s lost its CRTC", - conn->output.name); - conn->state = WLR_DRM_CONN_NEEDS_MODESET; - wlr_output_update_enabled(&conn->output, false); - conn->desired_mode = conn->output.current_mode; - wlr_output_update_mode(&conn->output, NULL); - continue; - } - if (!init_drm_plane_surfaces(conn->crtc->primary, drm, mode->width, mode->height, drm->renderer.gbm_format)) { wlr_log(WLR_ERROR, "Failed to initialize renderer for plane"); @@ -1153,11 +1098,6 @@ static void realloc_crtcs(struct wlr_drm_backend *drm, bool *changed_outputs) { wlr_output_damage_whole(&conn->output); } - -free_changed_outputs: - if (changed_local) { - free(changed_outputs); - } } static uint32_t get_possible_crtcs(int fd, drmModeRes *res, @@ -1392,25 +1332,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) { } } - bool changed_outputs[wl_list_length(&drm->outputs) + 1]; - memset(changed_outputs, false, sizeof(changed_outputs)); - for (size_t i = 0; i < new_outputs_len; ++i) { - struct wlr_drm_connector *conn = new_outputs[i]; - - ssize_t pos = -1; - struct wlr_drm_connector *c; - wl_list_for_each(c, &drm->outputs, link) { - ++pos; - if (c == conn) { - break; - } - } - assert(pos >= 0); - - changed_outputs[pos] = true; - } - - realloc_crtcs(drm, changed_outputs); + realloc_crtcs(drm); for (size_t i = 0; i < new_outputs_len; ++i) { struct wlr_drm_connector *conn = new_outputs[i]; @@ -1536,23 +1458,7 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { switch (conn->state) { case WLR_DRM_CONN_CONNECTED: - case WLR_DRM_CONN_CLEANUP:; - struct wlr_drm_crtc *crtc = conn->crtc; - if (crtc != NULL) { - for (int i = 0; i < 3; ++i) { - if (!crtc->planes[i]) { - continue; - } - - finish_drm_surface(&crtc->planes[i]->surf); - finish_drm_surface(&crtc->planes[i]->mgpu_surf); - if (crtc->planes[i]->id == 0) { - free(crtc->planes[i]); - crtc->planes[i] = NULL; - } - } - } - + case WLR_DRM_CONN_CLEANUP: conn->output.current_mode = NULL; conn->desired_mode = NULL; struct wlr_drm_mode *mode, *tmp; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 99120852..bc1c2933 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -22,8 +22,6 @@ struct wlr_drm_plane { uint32_t type; uint32_t id; - uint32_t possible_crtcs; - struct wlr_drm_surface surf; struct wlr_drm_surface mgpu_surf; @@ -49,14 +47,15 @@ struct wlr_drm_crtc { // Legacy only drmModeCrtc *legacy_crtc; - union { - struct { - struct wlr_drm_plane *overlay; - struct wlr_drm_plane *primary; - struct wlr_drm_plane *cursor; - }; - struct wlr_drm_plane *planes[3]; - }; + struct wlr_drm_plane *primary; + struct wlr_drm_plane *cursor; + + /* + * We don't support overlay planes yet, but we keep track of them to + * give to DRM lease clients. + */ + size_t num_overlays; + uint32_t *overlays; union wlr_drm_crtc_props props; @@ -78,26 +77,6 @@ struct wlr_drm_backend { size_t num_crtcs; struct wlr_drm_crtc *crtcs; - size_t num_planes; - struct wlr_drm_plane *planes; - - union { - struct { - size_t num_overlay_planes; - size_t num_primary_planes; - size_t num_cursor_planes; - }; - size_t num_type_planes[3]; - }; - - union { - struct { - struct wlr_drm_plane *overlay_planes; - struct wlr_drm_plane *primary_planes; - struct wlr_drm_plane *cursor_planes; - }; - struct wlr_drm_plane *type_planes[3]; - }; struct wl_display *display; struct wl_event_source *drm_event;