diff --git a/backend/drm/backend.c b/backend/drm/backend.c index a2c71317..4abcc817 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -12,8 +12,8 @@ #include #include #include -#include "backend/udev.h" -#include "backend/drm.h" +#include +#include "drm.h" static bool wlr_drm_backend_init(struct wlr_backend_state *state) { wlr_drm_scan_connectors(state); @@ -131,6 +131,15 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, state->session_signal.notify = session_signal; wl_signal_add(&session->session_signal, &state->session_signal); + if (drmSetClientCap(state->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { + wlr_log(L_INFO, "DRM universal planes unsupported"); + } + if (drmSetClientCap(state->fd, DRM_CLIENT_CAP_ATOMIC, 1)) { + wlr_log(L_INFO, "Atomic modesetting unsupported"); + } + + wlr_drm_init_resources(state); + // TODO: what is the difference between the per-output renderer and this // one? if (!wlr_drm_renderer_init(&state->renderer, state->fd)) { diff --git a/backend/drm/drm-properties.c b/backend/drm/drm-properties.c index 3e089c31..9310ffdd 100644 --- a/backend/drm/drm-properties.c +++ b/backend/drm/drm-properties.c @@ -49,10 +49,10 @@ static const struct prop_info plane_info[] = { }; static int cmp_prop_info(const void *arg1, const void *arg2) { - const struct prop_info *a = arg1; - const struct prop_info *b = arg2; + const char *key = arg1; + const struct prop_info *elem = arg2; - return strcmp(a->name, b->name); + return strcmp(key, elem->name); } static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result, @@ -97,3 +97,47 @@ bool wlr_drm_get_plane_props(int fd, uint32_t id, union wlr_drm_plane_props *out return scan_properties(fd, id, DRM_MODE_OBJECT_PLANE, out->props, plane_info, sizeof(plane_info) / sizeof(plane_info[0])); } + +bool wlr_drm_get_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret) { + drmModeObjectProperties *props = drmModeObjectGetProperties(fd, obj, DRM_MODE_OBJECT_ANY); + if (!props) { + return false; + } + + bool found = false; + + for (uint32_t i = 0; i < props->count_props; ++i) { + if (props->props[i] == prop) { + *ret = props->prop_values[i]; + found = true; + break; + } + } + + drmModeFreeObjectProperties(props); + return found; +} + +void *wlr_drm_get_prop_blob(int fd, uint32_t obj, uint32_t prop, size_t *ret_len) { + uint64_t blob_id; + if (!wlr_drm_get_prop(fd, obj, prop, &blob_id)) { + return NULL; + } + + drmModePropertyBlobRes *blob = drmModeGetPropertyBlob(fd, blob_id); + if (!blob) { + return NULL; + } + + void *ptr = malloc(blob->length); + if (!ptr) { + drmModeFreePropertyBlob(blob); + return NULL; + } + + memcpy(ptr, blob->data, blob->length); + *ret_len = blob->length; + + drmModeFreePropertyBlob(blob); + return ptr; +} diff --git a/backend/drm/drm-properties.h b/backend/drm/drm-properties.h index 99791958..287fc1e0 100644 --- a/backend/drm/drm-properties.h +++ b/backend/drm/drm-properties.h @@ -6,7 +6,7 @@ /* * These types contain the property ids for several DRM objects. - * See https://01.org/linuxgraphics/gfx-docs/drm/drm-kms-properties.html + * See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#kms-properties * for more details. */ @@ -56,4 +56,7 @@ bool wlr_drm_get_connector_props(int fd, uint32_t id, union wlr_drm_connector_pr bool wlr_drm_get_crtc_props(int fd, uint32_t id, union wlr_drm_crtc_props *out); bool wlr_drm_get_plane_props(int fd, uint32_t id, union wlr_drm_plane_props *out); +bool wlr_drm_get_prop(int fd, uint32_t obj, uint32_t prop, uint64_t *ret); +void *wlr_drm_get_prop_blob(int fd, uint32_t obj, uint32_t prop, size_t *ret_len); + #endif diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 6e969788..7c27c046 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -15,7 +15,7 @@ #include #include #include -#include "backend/drm.h" +#include "drm.h" static const char *conn_name[] = { [DRM_MODE_CONNECTOR_Unknown] = "Unknown", @@ -37,6 +37,137 @@ static const char *conn_name[] = { [DRM_MODE_CONNECTOR_DSI] = "DSI", }; +static int cmp_plane(const void *arg1, const void *arg2) +{ + const struct wlr_drm_plane *a = arg1; + const struct wlr_drm_plane *b = arg2; + + return (int)a->type - (int)b->type; +} + +static bool init_planes(struct wlr_backend_state *drm) +{ + drmModePlaneRes *plane_res = drmModeGetPlaneResources(drm->fd); + if (!plane_res) { + wlr_log_errno(L_ERROR, "Failed to get DRM plane resources"); + return false; + } + + wlr_log(L_INFO, "Found %"PRIu32" DRM planes", plane_res->count_planes); + + if (plane_res->count_planes == 0) { + drmModeFreePlaneResources(plane_res); + return true; + } + + size_t num_planes = plane_res->count_planes; + struct wlr_drm_plane *planes = calloc(num_planes, sizeof(*planes)); + if (!planes) { + wlr_log_errno(L_ERROR, "Allocation failed"); + goto error_res; + } + + size_t num_overlay = 0; + size_t num_primary = 0; + size_t num_cursor = 0; + + for (size_t i = 0; i < num_planes; ++i) { + struct wlr_drm_plane *p = &planes[i]; + + drmModePlane *plane = drmModeGetPlane(drm->fd, plane_res->planes[i]); + if (!plane) { + wlr_log_errno(L_ERROR, "Failed to get DRM plane"); + goto error_planes; + } + + p->id = plane->plane_id; + p->possible_crtcs = plane->possible_crtcs; + uint64_t type; + + if (!wlr_drm_get_plane_props(drm->fd, p->id, &p->props) || + !wlr_drm_get_prop(drm->fd, p->id, p->props.type, &type)) { + drmModeFreePlane(plane); + goto error_planes; + } + + p->type = type; + + switch (type) { + case DRM_PLANE_TYPE_OVERLAY: + ++num_overlay; + break; + case DRM_PLANE_TYPE_PRIMARY: + ++num_primary; + break; + case DRM_PLANE_TYPE_CURSOR: + ++num_cursor; + break; + } + + drmModeFreePlane(plane); + } + + wlr_log(L_INFO, "(%zu overlay, %zu primary, %zu cursor)", + num_overlay, num_primary, num_cursor); + + qsort(planes, num_planes, sizeof(*planes), cmp_plane); + + drm->num_planes = num_planes; + drm->num_overlay_planes = num_overlay; + drm->num_primary_planes = num_primary; + drm->num_cursor_planes = num_cursor; + + drm->planes = planes; + drm->overlay_planes = planes; + drm->primary_planes = planes + num_overlay; + drm->cursor_planes = planes + num_overlay + num_primary; + + return true; + +error_planes: + free(planes); +error_res: + drmModeFreePlaneResources(plane_res); + return false; +} + +bool wlr_drm_init_resources(struct wlr_backend_state *drm) { + drmModeRes *res = drmModeGetResources(drm->fd); + if (!res) { + wlr_log_errno(L_ERROR, "Failed to get DRM resources"); + return false; + } + + wlr_log(L_INFO, "Found %d DRM CRTCs", res->count_crtcs); + + drm->num_crtcs = res->count_crtcs; + drm->crtcs = calloc(drm->num_crtcs, sizeof(drm->crtcs[0])); + if (!drm->crtcs) { + wlr_log_errno(L_ERROR, "Allocation failed"); + goto error_res; + } + + for (size_t i = 0; i < drm->num_crtcs; ++i) { + struct wlr_drm_crtc *crtc = &drm->crtcs[i]; + crtc->id = res->crtcs[i]; + wlr_drm_get_crtc_props(drm->fd, crtc->id, &crtc->props); + } + + if (!init_planes(drm)) { + goto error_crtcs; + } + + drmModeFreeResources(res); + + return true; + +error_crtcs: + free(drm->crtcs); +error_res: + drmModeFreeResources(res); + return false; +} + bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd) { renderer->gbm = gbm_create_device(fd); if (!renderer->gbm) { diff --git a/include/backend/drm.h b/backend/drm/drm.h similarity index 68% rename from include/backend/drm.h rename to backend/drm/drm.h index ecdd945b..c5d32254 100644 --- a/include/backend/drm.h +++ b/backend/drm/drm.h @@ -14,8 +14,37 @@ #include #include -#include "backend/egl.h" -#include "backend/udev.h" +#include +#include +#include "drm-properties.h" + +struct wlr_drm_plane { + uint32_t type; + uint32_t id; + uint32_t fb_id; + + uint32_t possible_crtcs; + + int32_t x, y; + uint32_t width, height; + + struct gbm_surface *gbm; + EGLSurface egl; + + struct gbm_bo *front; + struct gbm_bo *back; + + union wlr_drm_plane_props props; +}; + +struct wlr_drm_crtc { + uint32_t id; + struct wlr_drm_plane *primary; + struct wlr_drm_plane *overlay; + struct wlr_drm_plane *cursor; + + union wlr_drm_crtc_props props; +}; struct wlr_drm_renderer { int fd; @@ -30,6 +59,18 @@ struct wlr_backend_state { int fd; dev_t dev; + size_t num_crtcs; + struct wlr_drm_crtc *crtcs; + size_t num_planes; + struct wlr_drm_plane *planes; + + size_t num_overlay_planes; + struct wlr_drm_plane *overlay_planes; + size_t num_primary_planes; + struct wlr_drm_plane *primary_planes; + size_t num_cursor_planes; + struct wlr_drm_plane *cursor_planes; + struct wlr_backend *backend; struct wl_display *display; struct wl_event_source *drm_event; @@ -83,6 +124,7 @@ struct wlr_output_state { bool cleanup; }; +bool wlr_drm_init_resources(struct wlr_backend_state *drm); void wlr_drm_output_cleanup(struct wlr_output_state *output, bool restore); void wlr_drm_scan_connectors(struct wlr_backend_state *state);