diff options
author | Scott Anderson <ascent12@hotmail.com> | 2017-07-20 20:51:59 +1200 |
---|---|---|
committer | Scott Anderson <ascent12@hotmail.com> | 2017-08-06 15:49:02 +1200 |
commit | 7b772e1a4b8c7a06fbcf0ec57766af3a5384bf0c (patch) | |
tree | ae172598a5a8b8e20a61054475f0a16b02f28fa1 /backend/drm | |
parent | 601bbad5d83387336028c5a721e8e85fccbbf844 (diff) |
DRM resource initalisation
Diffstat (limited to 'backend/drm')
-rw-r--r-- | backend/drm/backend.c | 13 | ||||
-rw-r--r-- | backend/drm/drm-properties.c | 50 | ||||
-rw-r--r-- | backend/drm/drm-properties.h | 5 | ||||
-rw-r--r-- | backend/drm/drm.c | 133 | ||||
-rw-r--r-- | backend/drm/drm.h | 136 |
5 files changed, 330 insertions, 7 deletions
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 <wlr/interfaces/wlr_output.h> #include <wlr/util/list.h> #include <wlr/util/log.h> -#include "backend/udev.h" -#include "backend/drm.h" +#include <backend/udev.h> +#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 <wlr/backend/interface.h> #include <wlr/interfaces/wlr_output.h> #include <wlr/util/log.h> -#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/backend/drm/drm.h b/backend/drm/drm.h new file mode 100644 index 00000000..c5d32254 --- /dev/null +++ b/backend/drm/drm.h @@ -0,0 +1,136 @@ +#ifndef DRM_BACKEND_H +#define DRM_BACKEND_H + +#include <stdbool.h> +#include <stddef.h> +#include <stdint.h> +#include <wayland-server.h> +#include <xf86drmMode.h> +#include <EGL/egl.h> +#include <libudev.h> +#include <gbm.h> + +#include <wlr/backend/session.h> +#include <wlr/backend/drm.h> +#include <wlr/util/list.h> + +#include <backend/egl.h> +#include <backend/udev.h> +#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; + struct gbm_device *gbm; + struct wlr_egl egl; +}; + +bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd); +void wlr_drm_renderer_free(struct wlr_drm_renderer *renderer); + +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; + + struct wl_listener session_signal; + struct wl_listener drm_invalidated; + + uint32_t taken_crtcs; + list_t *outputs; + + struct wlr_drm_renderer renderer; + struct wlr_session *session; + struct wlr_udev *udev; +}; + +enum wlr_drm_output_state { + DRM_OUTPUT_DISCONNECTED, + DRM_OUTPUT_NEEDS_MODESET, + DRM_OUTPUT_CONNECTED, +}; + +struct wlr_output_mode_state { + struct wlr_wl_output_mode *wlr_mode; + drmModeModeInfo mode; +}; + +struct wlr_output_state { + struct wlr_output *wlr_output; + enum wlr_drm_output_state state; + uint32_t connector; + + struct { + uint32_t dpms; + } props; + + uint32_t width; + uint32_t height; + + uint32_t crtc; + drmModeCrtc *old_crtc; + + struct wlr_drm_renderer *renderer; + EGLSurface *egl; + struct gbm_surface *gbm; + struct gbm_bo *bo[2]; + struct gbm_bo *cursor_bo[2]; + int current_cursor; + uint32_t cursor_width, cursor_height; + + bool pageflip_pending; + 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); +int wlr_drm_event(int fd, uint32_t mask, void *data); + +void wlr_drm_output_start_renderer(struct wlr_output_state *output); +void wlr_drm_output_pause_renderer(struct wlr_output_state *output); + +#endif |