aboutsummaryrefslogtreecommitdiff
path: root/backend
diff options
context:
space:
mode:
authorScott Anderson <ascent12@hotmail.com>2017-07-20 20:51:59 +1200
committerScott Anderson <ascent12@hotmail.com>2017-08-06 15:49:02 +1200
commit7b772e1a4b8c7a06fbcf0ec57766af3a5384bf0c (patch)
treeae172598a5a8b8e20a61054475f0a16b02f28fa1 /backend
parent601bbad5d83387336028c5a721e8e85fccbbf844 (diff)
DRM resource initalisation
Diffstat (limited to 'backend')
-rw-r--r--backend/drm/backend.c13
-rw-r--r--backend/drm/drm-properties.c50
-rw-r--r--backend/drm/drm-properties.h5
-rw-r--r--backend/drm/drm.c133
-rw-r--r--backend/drm/drm.h136
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