diff options
author | Drew DeVault <sir@cmpwn.com> | 2017-10-02 08:46:06 -0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-10-02 08:46:06 -0400 |
commit | 87a0cb7ba37eed29662ec16ce95493a0238ef660 (patch) | |
tree | 95554cb777848ce7246b651c09740d307bcdd506 /backend | |
parent | aa8a4f12b7e7ea8c3a1876f0585dd6171f8cb705 (diff) | |
parent | 9ec9edc40d4694dedfd7f00eb9106ce5ed133239 (diff) |
Merge pull request #182 from ascent12/drm-multi-gpu
DRM Multi-GPU
Diffstat (limited to 'backend')
-rw-r--r-- | backend/backend.c | 42 | ||||
-rw-r--r-- | backend/drm/atomic.c (renamed from backend/drm/drm-atomic.c) | 59 | ||||
-rw-r--r-- | backend/drm/backend.c | 120 | ||||
-rw-r--r-- | backend/drm/drm-legacy.c | 65 | ||||
-rw-r--r-- | backend/drm/drm.c | 790 | ||||
-rw-r--r-- | backend/drm/legacy.c | 66 | ||||
-rw-r--r-- | backend/drm/properties.c (renamed from backend/drm/drm-properties.c) | 2 | ||||
-rw-r--r-- | backend/drm/renderer.c | 250 | ||||
-rw-r--r-- | backend/drm/util.c (renamed from backend/drm/drm-util.c) | 2 | ||||
-rw-r--r-- | backend/meson.build | 9 | ||||
-rw-r--r-- | backend/session/session.c | 87 |
11 files changed, 824 insertions, 668 deletions
diff --git a/backend/backend.c b/backend/backend.c index ec309da4..d5cd1f70 100644 --- a/backend/backend.c +++ b/backend/backend.c @@ -91,15 +91,9 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { return NULL; } - int gpu = wlr_session_find_gpu(session); - if (gpu == -1) { - wlr_log(L_ERROR, "Failed to open DRM device"); - goto error_session; - } - backend = wlr_multi_backend_create(session); if (!backend) { - goto error_gpu; + goto error_session; } struct wlr_backend *libinput = wlr_libinput_backend_create(display, session); @@ -107,21 +101,37 @@ struct wlr_backend *wlr_backend_autocreate(struct wl_display *display) { goto error_multi; } - struct wlr_backend *drm = wlr_drm_backend_create(display, session, gpu); - if (!drm) { - goto error_libinput; + wlr_multi_backend_add(backend, libinput); + + int gpus[8]; + size_t num_gpus = wlr_session_find_gpus(session, 8, gpus); + struct wlr_backend *primary_drm = NULL; + wlr_log(L_INFO, "Found %zu GPUs", num_gpus); + + for (size_t i = 0; i < num_gpus; ++i) { + struct wlr_backend *drm = wlr_drm_backend_create(display, session, + gpus[i], primary_drm); + if (!drm) { + wlr_log(L_ERROR, "Failed to open DRM device"); + continue; + } + + if (!primary_drm) { + primary_drm = drm; + } + + wlr_multi_backend_add(backend, drm); + } + + if (!primary_drm) { + wlr_log(L_ERROR, "Failed to open any DRM device"); + goto error_multi; } - wlr_multi_backend_add(backend, libinput); - wlr_multi_backend_add(backend, drm); return backend; -error_libinput: - wlr_backend_destroy(libinput); error_multi: wlr_backend_destroy(backend); -error_gpu: - wlr_session_close_file(session, gpu); error_session: wlr_session_destroy(session); return NULL; diff --git a/backend/drm/drm-atomic.c b/backend/drm/atomic.c index 16c9c5c3..e7374a00 100644 --- a/backend/drm/drm-atomic.c +++ b/backend/drm/atomic.c @@ -2,8 +2,9 @@ #include <xf86drm.h> #include <xf86drmMode.h> #include <wlr/util/log.h> -#include "backend/drm.h" -#include "backend/drm-util.h" +#include "backend/drm/drm.h" +#include "backend/drm/iface.h" +#include "backend/drm/util.h" struct atomic { drmModeAtomicReq *req; @@ -43,23 +44,23 @@ static bool atomic_end(int drm_fd, struct atomic *atom) { } static bool atomic_commit(int drm_fd, struct atomic *atom, - struct wlr_drm_output *output, uint32_t flag, bool modeset) { + struct wlr_drm_connector *conn, uint32_t flag, bool modeset) { if (atom->failed) { return false; } uint32_t flags = DRM_MODE_PAGE_FLIP_EVENT | flag; - int ret = drmModeAtomicCommit(drm_fd, atom->req, flags, output); + int ret = drmModeAtomicCommit(drm_fd, atom->req, flags, conn); if (ret) { wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", - output->output.name, modeset ? "modeset" : "pageflip"); + conn->output.name, modeset ? "modeset" : "pageflip"); // Try to commit without new changes drmModeAtomicSetCursor(atom->req, atom->cursor); - if (drmModeAtomicCommit(drm_fd, atom->req, flags, output)) { + if (drmModeAtomicCommit(drm_fd, atom->req, flags, conn)) { wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", - output->output.name, modeset ? "modeset" : "pageflip"); + conn->output.name, modeset ? "modeset" : "pageflip"); } } @@ -83,10 +84,10 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_plane *plane, // The src_* properties are in 16.16 fixed point atomic_add(atom, id, props->src_x, 0); atomic_add(atom, id, props->src_y, 0); - atomic_add(atom, id, props->src_w, plane->width << 16); - atomic_add(atom, id, props->src_h, plane->height << 16); - atomic_add(atom, id, props->crtc_w, plane->width); - atomic_add(atom, id, props->crtc_h, plane->height); + atomic_add(atom, id, props->src_w, plane->surf.width << 16); + atomic_add(atom, id, props->src_h, plane->surf.height << 16); + atomic_add(atom, id, props->crtc_w, plane->surf.width); + atomic_add(atom, id, props->crtc_h, plane->surf.height); atomic_add(atom, id, props->fb_id, fb_id); atomic_add(atom, id, props->crtc_id, crtc_id); if (set_crtc_xy) { @@ -95,16 +96,16 @@ static void set_plane_props(struct atomic *atom, struct wlr_drm_plane *plane, } } -static bool atomic_crtc_pageflip(struct wlr_drm_backend *backend, - struct wlr_drm_output *output, +static bool atomic_crtc_pageflip(struct wlr_drm_backend *drm, + struct wlr_drm_connector *conn, struct wlr_drm_crtc *crtc, uint32_t fb_id, drmModeModeInfo *mode) { if (mode) { if (crtc->mode_id) { - drmModeDestroyPropertyBlob(backend->fd, crtc->mode_id); + drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } - if (drmModeCreatePropertyBlob(backend->fd, mode, sizeof(*mode), &crtc->mode_id)) { + if (drmModeCreatePropertyBlob(drm->fd, mode, sizeof(*mode), &crtc->mode_id)) { wlr_log_errno(L_ERROR, "Unable to create property blob"); return false; } @@ -113,29 +114,29 @@ static bool atomic_crtc_pageflip(struct wlr_drm_backend *backend, struct atomic atom; atomic_begin(crtc, &atom); - atomic_add(&atom, output->connector, output->props.crtc_id, crtc->id); + atomic_add(&atom, conn->id, conn->props.crtc_id, crtc->id); atomic_add(&atom, crtc->id, crtc->props.mode_id, crtc->mode_id); atomic_add(&atom, crtc->id, crtc->props.active, 1); set_plane_props(&atom, crtc->primary, crtc->id, fb_id, true); - return atomic_commit(backend->fd, &atom, output, + return atomic_commit(drm->fd, &atom, conn, mode ? DRM_MODE_ATOMIC_ALLOW_MODESET : DRM_MODE_ATOMIC_NONBLOCK, mode); } -static void atomic_conn_enable(struct wlr_drm_backend *backend, - struct wlr_drm_output *output, bool enable) { - struct wlr_drm_crtc *crtc = output->crtc; +static void atomic_conn_enable(struct wlr_drm_backend *drm, + struct wlr_drm_connector *conn, bool enable) { + struct wlr_drm_crtc *crtc = conn->crtc; struct atomic atom; atomic_begin(crtc, &atom); atomic_add(&atom, crtc->id, crtc->props.active, enable); - atomic_end(backend->fd, &atom); + atomic_end(drm->fd, &atom); } -bool legacy_crtc_set_cursor(struct wlr_drm_backend *backend, +bool legacy_crtc_set_cursor(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, struct gbm_bo *bo); -static bool atomic_crtc_set_cursor(struct wlr_drm_backend *backend, +static bool atomic_crtc_set_cursor(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, struct gbm_bo *bo) { if (!crtc || !crtc->cursor) { return true; @@ -144,7 +145,7 @@ static bool atomic_crtc_set_cursor(struct wlr_drm_backend *backend, struct wlr_drm_plane *plane = crtc->cursor; // We can't use atomic operations on fake planes if (plane->id == 0) { - return legacy_crtc_set_cursor(backend, crtc, bo); + return legacy_crtc_set_cursor(drm, crtc, bo); } struct atomic atom; @@ -158,18 +159,18 @@ static bool atomic_crtc_set_cursor(struct wlr_drm_backend *backend, atomic_add(&atom, plane->id, plane->props.crtc_id, 0); } - return atomic_end(backend->fd, &atom); + return atomic_end(drm->fd, &atom); } -bool legacy_crtc_move_cursor(struct wlr_drm_backend *backend, +bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, int x, int y); -static bool atomic_crtc_move_cursor(struct wlr_drm_backend *backend, +static bool atomic_crtc_move_cursor(struct wlr_drm_backend *drm, struct wlr_drm_crtc *crtc, int x, int y) { struct wlr_drm_plane *plane = crtc->cursor; // We can't use atomic operations on fake planes if (plane->id == 0) { - return legacy_crtc_move_cursor(backend, crtc, x, y); + return legacy_crtc_move_cursor(drm, crtc, x, y); } struct atomic atom; @@ -177,7 +178,7 @@ static bool atomic_crtc_move_cursor(struct wlr_drm_backend *backend, atomic_begin(crtc, &atom); atomic_add(&atom, plane->id, plane->props.crtc_x, x); atomic_add(&atom, plane->id, plane->props.crtc_y, y); - return atomic_end(backend->fd, &atom); + return atomic_end(drm->fd, &atom); } const struct wlr_drm_interface atomic_iface = { diff --git a/backend/drm/backend.c b/backend/drm/backend.c index 8d562007..468fca6e 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -6,45 +6,45 @@ #include <assert.h> #include <wayland-server.h> #include <xf86drm.h> -#include <sys/stat.h> #include <wlr/backend/session.h> #include <wlr/backend/interface.h> #include <wlr/interfaces/wlr_output.h> #include <wlr/util/list.h> #include <wlr/util/log.h> #include <wlr/egl.h> -#include "backend/drm.h" +#include "backend/drm/drm.h" -static bool wlr_drm_backend_start(struct wlr_backend *_backend) { - struct wlr_drm_backend *backend = (struct wlr_drm_backend *)_backend; - wlr_drm_scan_connectors(backend); +static bool wlr_drm_backend_start(struct wlr_backend *backend) { + struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend; + wlr_drm_scan_connectors(drm); return true; } -static void wlr_drm_backend_destroy(struct wlr_backend *_backend) { - if (!_backend) { +static void wlr_drm_backend_destroy(struct wlr_backend *backend) { + if (!backend) { return; } - struct wlr_drm_backend *backend = (struct wlr_drm_backend *)_backend; - wlr_drm_restore_outputs(backend); + struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend; + + wlr_drm_restore_outputs(drm); - for (size_t i = 0; backend->outputs && i < backend->outputs->length; ++i) { - struct wlr_drm_output *output = backend->outputs->items[i]; - wlr_output_destroy(&output->output); + for (size_t i = 0; drm->outputs && i < drm->outputs->length; ++i) { + struct wlr_drm_connector *conn = drm->outputs->items[i]; + wlr_output_destroy(&conn->output); } - wlr_drm_renderer_free(&backend->renderer); - wlr_drm_resources_free(backend); - wlr_session_close_file(backend->session, backend->fd); - wl_event_source_remove(backend->drm_event); - list_free(backend->outputs); - free(backend); + wlr_drm_renderer_finish(&drm->renderer); + wlr_drm_resources_free(drm); + wlr_session_close_file(drm->session, drm->fd); + wl_event_source_remove(drm->drm_event); + list_free(drm->outputs); + free(drm); } -static struct wlr_egl *wlr_drm_backend_get_egl(struct wlr_backend *_backend) { - struct wlr_drm_backend *backend = (struct wlr_drm_backend *)_backend; - return &backend->renderer.egl; +static struct wlr_egl *wlr_drm_backend_get_egl(struct wlr_backend *backend) { + struct wlr_drm_backend *drm = (struct wlr_drm_backend *)backend; + return &drm->renderer.egl; } static struct wlr_backend_impl backend_impl = { @@ -58,23 +58,22 @@ bool wlr_backend_is_drm(struct wlr_backend *b) { } static void session_signal(struct wl_listener *listener, void *data) { - struct wlr_drm_backend *backend = - wl_container_of(listener, backend, session_signal); + struct wlr_drm_backend *drm = wl_container_of(listener, drm, session_signal); struct wlr_session *session = data; if (session->active) { wlr_log(L_INFO, "DRM fd resumed"); - for (size_t i = 0; i < backend->outputs->length; ++i) { - struct wlr_drm_output *output = backend->outputs->items[i]; - wlr_drm_output_start_renderer(output); + for (size_t i = 0; i < drm->outputs->length; ++i) { + struct wlr_drm_connector *conn = drm->outputs->items[i]; + wlr_drm_connector_start_renderer(conn); - if (!output->crtc) { + if (!conn->crtc) { continue; } - struct wlr_drm_plane *plane = output->crtc->cursor; - backend->iface->crtc_set_cursor(backend, output->crtc, + struct wlr_drm_plane *plane = conn->crtc->cursor; + drm->iface->crtc_set_cursor(drm, conn->crtc, plane ? plane->cursor_bo : NULL); } } else { @@ -83,19 +82,19 @@ static void session_signal(struct wl_listener *listener, void *data) { } static void drm_invalidated(struct wl_listener *listener, void *data) { - struct wlr_drm_backend *backend = - wl_container_of(listener, backend, drm_invalidated); + struct wlr_drm_backend *drm = wl_container_of(listener, drm, drm_invalidated); - char *name = drmGetDeviceNameFromFd2(backend->fd); + char *name = drmGetDeviceNameFromFd2(drm->fd); wlr_log(L_DEBUG, "%s invalidated", name); free(name); - wlr_drm_scan_connectors(backend); + wlr_drm_scan_connectors(drm); } struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, - struct wlr_session *session, int gpu_fd) { + struct wlr_session *session, int gpu_fd, struct wlr_backend *parent) { assert(display && session && gpu_fd >= 0); + assert(!parent || wlr_backend_is_drm(parent)); char *name = drmGetDeviceNameFromFd2(gpu_fd); drmVersion *version = drmGetVersion(gpu_fd); @@ -103,69 +102,64 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display, free(name); drmFreeVersion(version); - struct wlr_drm_backend *backend = calloc(1, sizeof(struct wlr_drm_backend)); - if (!backend) { + struct wlr_drm_backend *drm = calloc(1, sizeof(struct wlr_drm_backend)); + if (!drm) { wlr_log_errno(L_ERROR, "Allocation failed"); return NULL; } - wlr_backend_init(&backend->backend, &backend_impl); + wlr_backend_init(&drm->backend, &backend_impl); - backend->session = session; - backend->outputs = list_create(); - if (!backend->outputs) { + drm->session = session; + drm->outputs = list_create(); + if (!drm->outputs) { wlr_log(L_ERROR, "Failed to allocate list"); goto error_backend; } - backend->fd = gpu_fd; - - struct stat st; - if (fstat(backend->fd, &st) < 0) { - wlr_log_errno(L_ERROR, "Stat failed"); - } - backend->dev = st.st_rdev; + drm->fd = gpu_fd; + drm->parent = (struct wlr_drm_backend *)parent; - backend->drm_invalidated.notify = drm_invalidated; - wlr_session_signal_add(session, gpu_fd, &backend->drm_invalidated); + drm->drm_invalidated.notify = drm_invalidated; + wlr_session_signal_add(session, gpu_fd, &drm->drm_invalidated); - backend->display = display; + drm->display = display; struct wl_event_loop *event_loop = wl_display_get_event_loop(display); - backend->drm_event = wl_event_loop_add_fd(event_loop, backend->fd, + drm->drm_event = wl_event_loop_add_fd(event_loop, drm->fd, WL_EVENT_READABLE, wlr_drm_event, NULL); - if (!backend->drm_event) { + if (!drm->drm_event) { wlr_log(L_ERROR, "Failed to create DRM event source"); goto error_fd; } - backend->session_signal.notify = session_signal; - wl_signal_add(&session->session_signal, &backend->session_signal); + drm->session_signal.notify = session_signal; + wl_signal_add(&session->session_signal, &drm->session_signal); - if (!wlr_drm_check_features(backend)) { + if (!wlr_drm_check_features(drm)) { goto error_event; } - if (!wlr_drm_resources_init(backend)) { + if (!wlr_drm_resources_init(drm)) { goto error_event; } - if (!wlr_drm_renderer_init(&backend->renderer, backend->fd)) { + if (!wlr_drm_renderer_init(drm, &drm->renderer)) { wlr_log(L_ERROR, "Failed to initialize renderer"); goto error_event; } - if (!wlr_egl_bind_display(&backend->renderer.egl, display)) { + if (!wlr_egl_bind_display(&drm->renderer.egl, display)) { wlr_log(L_INFO, "Failed to bind egl/wl display: %s", egl_error()); } - return &backend->backend; + return &drm->backend; error_event: - wl_event_source_remove(backend->drm_event); + wl_event_source_remove(drm->drm_event); error_fd: - wlr_session_close_file(backend->session, backend->fd); - list_free(backend->outputs); + wlr_session_close_file(drm->session, drm->fd); + list_free(drm->outputs); error_backend: - free(backend); + free(drm); return NULL; } diff --git a/backend/drm/drm-legacy.c b/backend/drm/drm-legacy.c deleted file mode 100644 index 9b7cd301..00000000 --- a/backend/drm/drm-legacy.c +++ /dev/null @@ -1,65 +0,0 @@ -#include <gbm.h> -#include <xf86drm.h> -#include <xf86drmMode.h> -#include <wlr/util/log.h> -#include "backend/drm.h" -#include "backend/drm-util.h" - -static bool legacy_crtc_pageflip(struct wlr_drm_backend *backend, - struct wlr_drm_output *output, struct wlr_drm_crtc *crtc, - uint32_t fb_id, drmModeModeInfo *mode) { - if (mode) { - if (drmModeSetCrtc(backend->fd, crtc->id, fb_id, 0, 0, - &output->connector, 1, mode)) { - wlr_log_errno(L_ERROR, "%s: Failed to set CRTC", output->output.name); - return false; - } - } - - if (drmModePageFlip(backend->fd, crtc->id, fb_id, DRM_MODE_PAGE_FLIP_EVENT, output)) { - wlr_log_errno(L_ERROR, "%s: Failed to page flip", output->output.name); - return false; - } - - return true; -} - -static void legacy_conn_enable(struct wlr_drm_backend *backend, - struct wlr_drm_output *output, bool enable) { - drmModeConnectorSetProperty(backend->fd, output->connector, output->props.dpms, - enable ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF); -} - -bool legacy_crtc_set_cursor(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, struct gbm_bo *bo) { - if (!crtc || !crtc->cursor) { - return true; - } - - if (!bo) { - drmModeSetCursor(backend->fd, crtc->id, 0, 0, 0); - return true; - } - - struct wlr_drm_plane *plane = crtc->cursor; - - if (drmModeSetCursor(backend->fd, crtc->id, gbm_bo_get_handle(bo).u32, - plane->width, plane->height)) { - wlr_log_errno(L_ERROR, "Failed to set hardware cursor"); - return false; - } - - return true; -} - -bool legacy_crtc_move_cursor(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, int x, int y) { - return !drmModeMoveCursor(backend->fd, crtc->id, x, y); -} - -const struct wlr_drm_interface legacy_iface = { - .conn_enable = legacy_conn_enable, - .crtc_pageflip = legacy_crtc_pageflip, - .crtc_set_cursor = legacy_crtc_set_cursor, - .crtc_move_cursor = legacy_crtc_move_cursor, -}; diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 1a656172..1a5fea9f 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -20,27 +20,25 @@ #include <wlr/render/matrix.h> #include <wlr/render/gles2.h> #include <wlr/render.h> -#include "backend/drm.h" -#include "backend/drm-util.h" +#include "backend/drm/drm.h" +#include "backend/drm/iface.h" +#include "backend/drm/util.h" -bool wlr_drm_check_features(struct wlr_drm_backend *backend) { - extern const struct wlr_drm_interface legacy_iface; - extern const struct wlr_drm_interface atomic_iface; - - if (drmSetClientCap(backend->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { +bool wlr_drm_check_features(struct wlr_drm_backend *drm) { + if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { wlr_log(L_ERROR, "DRM universal planes unsupported"); return false; } if (getenv("WLR_DRM_NO_ATOMIC")) { wlr_log(L_DEBUG, "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); - backend->iface = &legacy_iface; - } else if (drmSetClientCap(backend->fd, DRM_CLIENT_CAP_ATOMIC, 1)) { + drm->iface = &legacy_iface; + } else if (drmSetClientCap(drm->fd, DRM_CLIENT_CAP_ATOMIC, 1)) { wlr_log(L_DEBUG, "Atomic modesetting unsupported, using legacy DRM interface"); - backend->iface = &legacy_iface; + drm->iface = &legacy_iface; } else { wlr_log(L_DEBUG, "Using atomic DRM interface"); - backend->iface = &atomic_iface; + drm->iface = &atomic_iface; } return true; @@ -53,8 +51,8 @@ static int cmp_plane(const void *arg1, const void *arg2) { return (int)a->type - (int)b->type; } -static bool init_planes(struct wlr_drm_backend *backend) { - drmModePlaneRes *plane_res = drmModeGetPlaneResources(backend->fd); +static bool init_planes(struct wlr_drm_backend *drm) { + drmModePlaneRes *plane_res = drmModeGetPlaneResources(drm->fd); if (!plane_res) { wlr_log_errno(L_ERROR, "Failed to get DRM plane resources"); return false; @@ -67,17 +65,17 @@ static bool init_planes(struct wlr_drm_backend *backend) { return true; } - backend->num_planes = plane_res->count_planes; - backend->planes = calloc(backend->num_planes, sizeof(*backend->planes)); - if (!backend->planes) { + drm->num_planes = plane_res->count_planes; + drm->planes = calloc(drm->num_planes, sizeof(*drm->planes)); + if (!drm->planes) { wlr_log_errno(L_ERROR, "Allocation failed"); goto error_res; } - for (size_t i = 0; i < backend->num_planes; ++i) { - struct wlr_drm_plane *p = &backend->planes[i]; + for (size_t i = 0; i < drm->num_planes; ++i) { + struct wlr_drm_plane *p = &drm->planes[i]; - drmModePlane *plane = drmModeGetPlane(backend->fd, plane_res->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; @@ -87,44 +85,43 @@ static bool init_planes(struct wlr_drm_backend *backend) { p->possible_crtcs = plane->possible_crtcs; uint64_t type; - if (!wlr_drm_get_plane_props(backend->fd, p->id, &p->props) || - !wlr_drm_get_prop(backend->fd, p->id, p->props.type, &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; - backend->num_type_planes[type]++; + drm->num_type_planes[type]++; drmModeFreePlane(plane); } wlr_log(L_INFO, "(%zu overlay, %zu primary, %zu cursor)", - backend->num_overlay_planes, - backend->num_primary_planes, - backend->num_cursor_planes); + drm->num_overlay_planes, + drm->num_primary_planes, + drm->num_cursor_planes); - qsort(backend->planes, backend->num_planes, - sizeof(*backend->planes), cmp_plane); + qsort(drm->planes, drm->num_planes, sizeof(*drm->planes), cmp_plane); - backend->overlay_planes = backend->planes; - backend->primary_planes = backend->overlay_planes - + backend->num_overlay_planes; - backend->cursor_planes = backend->primary_planes - + backend->num_primary_planes; + 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(backend->planes); + free(drm->planes); error_res: drmModeFreePlaneResources(plane_res); return false; } -bool wlr_drm_resources_init(struct wlr_drm_backend *backend) { - drmModeRes *res = drmModeGetResources(backend->fd); +bool wlr_drm_resources_init(struct wlr_drm_backend *drm) { + drmModeRes *res = drmModeGetResources(drm->fd); if (!res) { wlr_log_errno(L_ERROR, "Failed to get DRM resources"); return false; @@ -132,20 +129,20 @@ bool wlr_drm_resources_init(struct wlr_drm_backend *backend) { wlr_log(L_INFO, "Found %d DRM CRTCs", res->count_crtcs); - backend->num_crtcs = res->count_crtcs; - backend->crtcs = calloc(backend->num_crtcs, sizeof(backend->crtcs[0])); - if (!backend->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 < backend->num_crtcs; ++i) { - struct wlr_drm_crtc *crtc = &backend->crtcs[i]; + 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(backend->fd, crtc->id, &crtc->props); + wlr_drm_get_crtc_props(drm->fd, crtc->id, &crtc->props); } - if (!init_planes(backend)) { + if (!init_planes(drm)) { goto error_crtcs; } @@ -154,311 +151,185 @@ bool wlr_drm_resources_init(struct wlr_drm_backend *backend) { return true; error_crtcs: - free(backend->crtcs); + free(drm->crtcs); error_res: drmModeFreeResources(res); return false; } -void wlr_drm_resources_free(struct wlr_drm_backend *backend) { - if (!backend) { +void wlr_drm_resources_free(struct wlr_drm_backend *drm) { + if (!drm) { return; } - for (size_t i = 0; i < backend->num_crtcs; ++i) { - struct wlr_drm_crtc *crtc = &backend->crtcs[i]; + + for (size_t i = 0; i < drm->num_crtcs; ++i) { + struct wlr_drm_crtc *crtc = &drm->crtcs[i]; drmModeAtomicFree(crtc->atomic); if (crtc->mode_id) { - drmModeDestroyPropertyBlob(backend->fd, crtc->mode_id); + drmModeDestroyPropertyBlob(drm->fd, crtc->mode_id); } } - free(backend->crtcs); - free(backend->planes); -} - -bool wlr_drm_renderer_init(struct wlr_drm_renderer *renderer, int fd) { - renderer->gbm = gbm_create_device(fd); - if (!renderer->gbm) { - wlr_log(L_ERROR, "Failed to create GBM device: %s", strerror(errno)); - return false; - } - - if (!wlr_egl_init(&renderer->egl, EGL_PLATFORM_GBM_MESA, - GBM_FORMAT_ARGB8888, renderer->gbm)) { - gbm_device_destroy(renderer->gbm); - return false; - } - - renderer->fd = fd; - return true; + free(drm->crtcs); + free(drm->planes); } -void wlr_drm_renderer_free(struct wlr_drm_renderer *renderer) { - if (!renderer) { - return; - } - - wlr_egl_free(&renderer->egl); - gbm_device_destroy(renderer->gbm); +static void wlr_drm_connector_make_current(struct wlr_output *output) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + wlr_drm_surface_make_current(&conn->crtc->primary->surf); } -static bool wlr_drm_plane_renderer_init(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane, uint32_t width, uint32_t height, uint32_t format, uint32_t flags) { - if (plane->width == width && plane->height == height) { - return true; - } - - plane->width = width; - plane->height = height; - - plane->gbm = gbm_surface_create(renderer->gbm, width, height, - format, GBM_BO_USE_RENDERING | flags); - if (!plane->gbm) { - wlr_log_errno(L_ERROR, "Failed to create GBM surface for plane"); - return false; - } - - plane->egl = wlr_egl_create_surface(&renderer->egl, plane->gbm); - if (plane->egl == EGL_NO_SURFACE) { - wlr_log(L_ERROR, "Failed to create EGL surface for plane"); - return false; - } - - return true; -} - -static void wlr_drm_plane_renderer_free(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane) { - if (!renderer || !plane) { - return; - } - - eglMakeCurrent(renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT); - - if (plane->front) { - gbm_surface_release_buffer(plane->gbm, plane->front); - } - if (plane->back) { - gbm_surface_release_buffer(plane->gbm, plane->back); - } - - if (plane->egl) { - eglDestroySurface(renderer->egl.display, plane->egl); - } - if (plane->gbm) { - gbm_surface_destroy(plane->gbm); - } - - if (plane->wlr_tex) { - wlr_texture_destroy(plane->wlr_tex); - } - if (plane->wlr_rend) { - wlr_renderer_destroy(plane->wlr_rend); - } - if (plane->cursor_bo) { - gbm_bo_destroy(plane->cursor_bo); - } - - plane->width = 0; - plane->height = 0; - plane->egl = EGL_NO_SURFACE; - plane->gbm = NULL; - plane->front = NULL; - plane->back = NULL; - plane->wlr_rend = NULL; - plane->wlr_tex = NULL; - plane->cursor_bo = NULL; -} - -static void wlr_drm_plane_make_current(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane) { - eglMakeCurrent(renderer->egl.display, plane->egl, plane->egl, - renderer->egl.context); -} - -static void wlr_drm_plane_swap_buffers(struct wlr_drm_renderer *renderer, - struct wlr_drm_plane *plane) { - if (plane->front) { - gbm_surface_release_buffer(plane->gbm, plane->front); - } - - eglSwapBuffers(renderer->egl.display, plane->egl); +static void wlr_drm_connector_swap_buffers(struct wlr_output *output) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + struct wlr_drm_backend *drm = conn->drm; - plane->front = plane->back; - plane->back = gbm_surface_lock_front_buffer(plane->gbm); -} - -static void wlr_drm_output_make_current(struct wlr_output *_output) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - wlr_drm_plane_make_current(output->renderer, output->crtc->primary); -} - -static void wlr_drm_output_swap_buffers(struct wlr_output *_output) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - struct wlr_drm_backend *backend = - wl_container_of(output->renderer, backend, renderer); - struct wlr_drm_renderer *renderer = output->renderer; - struct wlr_drm_crtc *crtc = output->crtc; + struct wlr_drm_crtc *crtc = conn->crtc; struct wlr_drm_plane *plane = crtc->primary; - wlr_drm_plane_swap_buffers(renderer, plane); + struct gbm_bo *bo = wlr_drm_surface_swap_buffers(&plane->surf); + if (drm->parent) { + bo = wlr_drm_surface_mgpu_copy(&plane->mgpu_surf, bo); + } - uint32_t fb_id = get_fb_for_bo(plane->back); + uint32_t fb_id = get_fb_for_bo(bo); - if (backend->iface->crtc_pageflip(backend, output, crtc, fb_id, NULL)) { - output->pageflip_pending = true; + if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { + conn->pageflip_pending = true; } else { - wl_event_source_timer_update(output->retry_pageflip, - 1000.0f / output->output.current_mode->refresh); + wl_event_source_timer_update(conn->retry_pageflip, + 1000.0f / conn->output.current_mode->refresh); } } -static void wlr_drm_output_set_gamma(struct wlr_output *_output, +static void wlr_drm_connector_set_gamma(struct wlr_output *output, uint16_t size, uint16_t *r, uint16_t *g, uint16_t *b) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - struct wlr_drm_backend *backend = - wl_container_of(output->renderer, backend, renderer); - drmModeCrtcSetGamma(backend->fd, output->crtc->id, size, r, g, b); + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + drmModeCrtcSetGamma(conn->drm->fd, conn->crtc->id, size, r, g, b); } -static uint16_t wlr_drm_output_get_gamma_size(struct wlr_output *_output) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - drmModeCrtc *crtc = output->old_crtc; - if (!crtc) { - return 0; - } - return crtc->gamma_size; +static uint16_t wlr_drm_connector_get_gamma_size(struct wlr_output *output) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + drmModeCrtc *crtc = conn->old_crtc; + return crtc ? crtc->gamma_size : 0; } -void wlr_drm_output_start_renderer(struct wlr_drm_output *output) { - if (output->state != WLR_DRM_OUTPUT_CONNECTED) { +void wlr_drm_connector_start_renderer(struct wlr_drm_connector *conn) { + if (conn->state != WLR_DRM_CONN_CONNECTED) { return; } - struct wlr_drm_backend *backend = - wl_container_of(output->renderer, backend, renderer); - struct wlr_drm_renderer *renderer = output->renderer; - struct wlr_drm_crtc *crtc = output->crtc; + struct wlr_drm_backend *drm = conn->drm; + struct wlr_drm_crtc *crtc = conn->crtc; struct wlr_drm_plane *plane = crtc->primary; - struct gbm_bo *bo = plane->front; - if (!bo) { - // Render a black frame to start the rendering loop - wlr_drm_plane_make_current(renderer, plane); - glViewport(0, 0, plane->width, plane->height); - glClearColor(0.0, 0.0, 0.0, 1.0); - glClear(GL_COLOR_BUFFER_BIT); - wlr_drm_plane_swap_buffers(renderer, plane); - - bo = plane->back; - } + struct gbm_bo *bo = wlr_drm_surface_get_front( + drm->parent ? &plane->mgpu_surf : &plane->surf); + uint32_t fb_id = get_fb_for_bo(bo); - struct wlr_drm_output_mode *_mode = - (struct wlr_drm_output_mode *)output->output.current_mode; - drmModeModeInfo *mode = &_mode->mode; - if (backend->iface->crtc_pageflip(backend, output, crtc, get_fb_for_bo(bo), mode)) { - output->pageflip_pending = true; + struct wlr_drm_mode *mode = (struct wlr_drm_mode *)conn->output.current_mode; + if (drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, &mode->drm_mode)) { + conn->pageflip_pending = true; } else { - wl_event_source_timer_update(output->retry_pageflip, - 1000.0f / output->output.current_mode->refresh); + wl_event_source_timer_update(conn->retry_pageflip, + 1000.0f / conn->output.current_mode->refresh); } } -static void wlr_drm_output_enable(struct wlr_output *_output, bool enable) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - struct wlr_drm_backend *backend = - wl_container_of(output->renderer, backend, renderer); - if (output->state != WLR_DRM_OUTPUT_CONNECTED) { +static void wlr_drm_connector_enable(struct wlr_output *output, bool enable) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + if (conn->state != WLR_DRM_CONN_CONNECTED) { return; } - backend->iface->conn_enable(backend, output, enable); + struct wlr_drm_backend *drm = conn->drm; + drm->iface->conn_enable(drm, conn, enable); if (enable) { - wlr_drm_output_start_renderer(output); + wlr_drm_connector_start_renderer(conn); } } -static void realloc_planes(struct wlr_drm_backend *backend, const uint32_t *crtc_in) { +static void realloc_planes(struct wlr_drm_backend *drm, const uint32_t *crtc_in) { // overlay, primary, cursor for (int type = 0; type < 3; ++type) { - if (backend->num_type_planes[type] == 0) { + if (drm->num_type_planes[type] == 0) { continue; } - uint32_t possible[backend->num_type_planes[type]]; - uint32_t crtc[backend->num_crtcs]; - uint32_t crtc_res[backend->num_crtcs]; + uint32_t possible[drm->num_type_planes[type]]; + uint32_t crtc[drm->num_crtcs]; + uint32_t crtc_res[drm->num_crtcs]; - for (size_t i = 0; i < backend->num_type_planes[type]; ++i) { - possible[i] = backend->type_planes[type][i].possible_crtcs; + 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 < backend->num_crtcs; ++i) { + for (size_t i = 0; i < drm->num_crtcs; ++i) { if (crtc_in[i] == UNMATCHED) { crtc[i] = SKIP; - } else if (backend->crtcs[i].planes[type]) { - crtc[i] = backend->crtcs[i].planes[type] - - backend->type_planes[type]; + } else if (drm->crtcs[i].planes[type]) { + crtc[i] = drm->crtcs[i].planes[type] + - drm->type_planes[type]; } else { crtc[i] = UNMATCHED; } } - match_obj(backend->num_type_planes[type], possible, - backend->num_crtcs, crtc, crtc_res); + match_obj(drm->num_type_planes[type], possible, + drm->num_crtcs, crtc, crtc_res); - for (size_t i = 0; i < backend->num_crtcs; ++i) { + 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 = &backend->crtcs[i]; + struct wlr_drm_crtc *c = &drm->crtcs[i]; struct wlr_drm_plane **old = &c->planes[type]; - struct wlr_drm_plane *new = &backend->type_planes[type][crtc_res[i]]; + struct wlr_drm_plane *new = &drm->type_planes[type][crtc_res[i]]; if (*old != new) { - wlr_drm_plane_renderer_free(&backend->renderer, *old); - wlr_drm_plane_renderer_free(&backend->renderer, new); + if (*old) { + wlr_drm_surface_finish(&(*old)->surf); + } + wlr_drm_surface_finish(&new->surf); *old = new; } } } } -static void realloc_crtcs(struct wlr_drm_backend *backend, - struct wlr_drm_output *output) { - uint32_t crtc[backend->num_crtcs]; - uint32_t crtc_res[backend->num_crtcs]; - uint32_t possible_crtc[backend->outputs->length]; +static void realloc_crtcs(struct wlr_drm_backend *drm, struct wlr_drm_connector *conn) { + uint32_t crtc[drm->num_crtcs]; + uint32_t crtc_res[drm->num_crtcs]; + uint32_t possible_crtc[drm->outputs->length]; - for (size_t i = 0; i < backend->num_crtcs; ++i) { + for (size_t i = 0; i < drm->num_crtcs; ++i) { crtc[i] = UNMATCHED; } memset(possible_crtc, 0, sizeof(possible_crtc)); ssize_t index = -1; - for (size_t i = 0; i < backend->outputs->length; ++i) { - struct wlr_drm_output *o = backend->outputs->items[i]; - if (o == output) { + for (size_t i = 0; i < drm->outputs->length; ++i) { + struct wlr_drm_connector *c = drm->outputs->items[i]; + if (c == conn) { index = i; } - if (o->state != WLR_DRM_OUTPUT_CONNECTED) { + if (c->state != WLR_DRM_CONN_CONNECTED) { continue; } - possible_crtc[i] = o->possible_crtc; - crtc[o->crtc - backend->crtcs] = i; + possible_crtc[i] = c->possible_crtc; + crtc[c->crtc - drm->crtcs] = i; } assert(index != -1); - possible_crtc[index] = output->possible_crtc; - match_obj(backend->outputs->length, possible_crtc, - backend->num_crtcs, crtc, crtc_res); + possible_crtc[index] = conn->possible_crtc; + match_obj(drm->outputs->length, possible_crtc, drm->num_crtcs, + crtc, crtc_res); bool matched = false; - for (size_t i = 0; i < backend->num_crtcs; ++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 && crtc_res[i] == UNMATCHED) { return; @@ -473,43 +344,35 @@ static void realloc_crtcs(struct wlr_drm_backend *backend, return; } - for (size_t i = 0; i < backend->num_crtcs; ++i) { + for (size_t i = 0; i < drm->num_crtcs; ++i) { if (crtc_res[i] == UNMATCHED) { continue; } if (crtc_res[i] != crtc[i]) { - struct wlr_drm_output *o = backend->outputs->items[crtc_res[i]]; - o->crtc = &backend->crtcs[i]; + struct wlr_drm_connector *c = drm->outputs->items[crtc_res[i]]; + c->crtc = &drm->crtcs[i]; } } - realloc_planes(backend, crtc_res); + realloc_planes(drm, crtc_res); } -static bool wlr_drm_output_set_mode(struct wlr_output *_output, - struct wlr_output_mode *mode) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - struct wlr_drm_backend *backend - = wl_container_of(output->renderer, backend, renderer); - - wlr_log(L_INFO, "Modesetting '%s' with '%ux%u@%u mHz'", output->output.name, - mode->width, mode->height, mode->refresh); - - drmModeConnector *conn = drmModeGetConnector(backend->fd, output->connector); +static uint32_t get_possible_crtcs(int fd, uint32_t conn_id) { + drmModeConnector *conn = drmModeGetConnector(fd, conn_id); if (!conn) { wlr_log_errno(L_ERROR, "Failed to get DRM connector"); - goto error_output; + return 0; } if (conn->connection != DRM_MODE_CONNECTED || conn->count_modes == 0) { - wlr_log(L_ERROR, "%s is not connected", output->output.name); - goto error_output; + wlr_log(L_ERROR, "Output is not connected"); + goto error_conn; } drmModeEncoder *enc = NULL; for (int i = 0; !enc && i < conn->count_encoders; ++i) { - enc = drmModeGetEncoder(backend->fd, conn->encoders[i]); + enc = drmModeGetEncoder(fd, conn->encoders[i]); } if (!enc) { @@ -517,77 +380,92 @@ static bool wlr_drm_output_set_mode(struct wlr_output *_output, goto error_conn; } - output->possible_crtc = enc->possible_crtcs; - realloc_crtcs(backend, output); + uint32_t ret = enc->possible_crtcs; + drmModeFreeEncoder(enc); + drmModeFreeConnector(conn); + return ret; + +error_conn: + drmModeFreeConnector(conn); + return 0; +} + +static bool wlr_drm_connector_set_mode(struct wlr_output *output, + struct wlr_output_mode *mode) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + struct wlr_drm_backend *drm = conn->drm; + + wlr_log(L_INFO, "Modesetting '%s' with '%ux%u@%u mHz'", conn->output.name, + mode->width, mode->height, mode->refresh); + + conn->possible_crtc = get_possible_crtcs(drm->fd, conn->id); + if (conn->possible_crtc == 0) { + goto error_conn; + } + + realloc_crtcs(drm, conn); - if (!output->crtc) { - wlr_log(L_ERROR, "Unable to match %s with a CRTC", output->output.name); - goto error_enc; + if (!conn->crtc) { + wlr_log(L_ERROR, "Unable to match %s with a CRTC", conn->output.name); + goto error_conn; } - struct wlr_drm_crtc *crtc = output->crtc; - wlr_log(L_DEBUG, "%s: crtc=%ju ovr=%jd pri=%jd cur=%jd", output->output.name, - crtc - backend->crtcs, - crtc->overlay ? crtc->overlay - backend->overlay_planes : -1, - crtc->primary ? crtc->primary - backend->primary_planes : -1, - crtc->cursor ? crtc->cursor - backend->cursor_planes : -1); + struct wlr_drm_crtc *crtc = conn->crtc; + wlr_log(L_DEBUG, "%s: crtc=%ju ovr=%jd pri=%jd cur=%jd", conn->output.name, + crtc - drm->crtcs, + crtc->overlay ? crtc->overlay - drm->overlay_planes : -1, + crtc->primary ? crtc->primary - drm->primary_planes : -1, + crtc->cursor ? crtc->cursor - drm->cursor_planes : -1); - output->state = WLR_DRM_OUTPUT_CONNECTED; - output->width = output->output.width = mode->width; - output->height = output->output.height = mode->height; - output->output.current_mode = mode; - wl_signal_emit(&output->output.events.resolution, &output->output); + conn->state = WLR_DRM_CONN_CONNECTED; + conn->output.width = mode->width; + conn->output.height = mode->height; + conn->output.current_mode = mode; + wl_signal_emit(&conn->output.events.resolution, &conn->output); // Since realloc_crtcs can deallocate planes on OTHER outputs, // we actually need to reinitalise all of them - for (size_t i = 0; i < backend->outputs->length; ++i) { - struct wlr_drm_output *output = backend->outputs->items[i]; - struct wlr_output_mode *mode = output->output.current_mode; - struct wlr_drm_crtc *crtc = output->crtc; + for (size_t i = 0; i < drm->outputs->length; ++i) { + struct wlr_drm_connector *conn = drm->outputs->items[i]; + struct wlr_output_mode *mode = conn->output.current_mode; + struct wlr_drm_crtc *crtc = conn->crtc; - if (output->state != WLR_DRM_OUTPUT_CONNECTED) { + if (conn->state != WLR_DRM_CONN_CONNECTED) { continue; } - if (!wlr_drm_plane_renderer_init(&backend->renderer, crtc->primary, - mode->width, mode->height, GBM_FORMAT_XRGB8888, - GBM_BO_USE_SCANOUT)) { + if (!wlr_drm_plane_surfaces_init(crtc->primary, drm, + mode->width, mode->height, GBM_FORMAT_XRGB8888)) { wlr_log(L_ERROR, "Failed to initalise renderer for plane"); - goto error_enc; + goto error_conn; } - wlr_drm_output_start_renderer(output); + wlr_drm_connector_start_renderer(conn); } - drmModeFreeEncoder(enc); - drmModeFreeConnector(conn); return true; -error_enc: - drmModeFreeEncoder(enc); error_conn: - drmModeFreeConnector(conn); -error_output: - wlr_drm_output_cleanup(output); + wlr_drm_connector_cleanup(conn); return false; } -static void wlr_drm_output_transform(struct wlr_output *output, +static void wlr_drm_connector_transform(struct wlr_output *output, enum wl_output_transform transform) { output->transform = transform; } -static bool wlr_drm_output_set_cursor(struct wlr_output *_output, +static bool wlr_drm_connector_set_cursor(struct wlr_output *output, const uint8_t *buf, int32_t stride, uint32_t width, uint32_t height) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - struct wlr_drm_backend *backend - = wl_container_of(output->renderer, backend, renderer); - struct wlr_drm_renderer *renderer = output->renderer; - struct wlr_drm_crtc *crtc = output->crtc; + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + struct wlr_drm_backend *drm = conn->drm; + struct wlr_drm_renderer *renderer = &drm->renderer; + + struct wlr_drm_crtc *crtc = conn->crtc; struct wlr_drm_plane *plane = crtc->cursor; if (!buf) { - return backend->iface->crtc_set_cursor(backend, crtc, NULL); + return drm->iface->crtc_set_cursor(drm, crtc, NULL); } // We don't have a real cursor plane, so we make a fake one @@ -600,12 +478,12 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, crtc->cursor = plane; } - if (!plane->gbm) { + if (!plane->surf.gbm) { int ret; uint64_t w, h; - ret = drmGetCap(backend->fd, DRM_CAP_CURSOR_WIDTH, &w); + ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_WIDTH, &w); w = ret ? 64 : w; - ret = drmGetCap(backend->fd, DRM_CAP_CURSOR_HEIGHT, &h); + ret = drmGetCap(drm->fd, DRM_CAP_CURSOR_HEIGHT, &h); h = ret ? 64 : h; if (width > w || height > h) { @@ -613,7 +491,7 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, return false; } - if (!wlr_drm_plane_renderer_init(renderer, plane, w, h, GBM_FORMAT_ARGB8888, 0)) { + if (!wlr_drm_surface_init(&plane->surf, renderer, w, h, GBM_FORMAT_ARGB8888, 0)) { wlr_log(L_ERROR, "Cannot allocate cursor resources"); return false; } @@ -627,12 +505,12 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, // OpenGL will read the pixels out upside down, // so we need to flip the image vertically - wlr_matrix_texture(plane->matrix, plane->width, plane->height, - output->output.transform ^ WL_OUTPUT_TRANSFORM_FLIPPED_180); + wlr_matrix_texture(plane->matrix, plane->surf.width, plane->surf.height, + conn->output.transform ^ WL_OUTPUT_TRANSFORM_FLIPPED_180); // TODO the image needs to be rotated depending on the output rotation - plane->wlr_rend = wlr_gles2_renderer_create(&backend->backend); + plane->wlr_rend = wlr_gles2_renderer_create(&drm->backend); if (!plane->wlr_rend) { return false; } @@ -655,12 +533,12 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, return false; } - wlr_drm_plane_make_current(renderer, plane); + wlr_drm_surface_make_current(&plane->surf); wlr_texture_upload_pixels(plane->wlr_tex, WL_SHM_FORMAT_ARGB8888, stride, width, height, buf); - glViewport(0, 0, plane->width, plane->height); + glViewport(0, 0, plane->surf.width, plane->surf.height); glClearColor(0.0, 0.0, 0.0, 0.0); glClear(GL_COLOR_BUFFER_BIT); @@ -670,26 +548,25 @@ static bool wlr_drm_output_set_cursor(struct wlr_output *_output, glFinish(); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, bo_stride); - glReadPixels(0, 0, plane->width, plane->height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bo_data); + glReadPixels(0, 0, plane->surf.width, plane->surf.height, GL_BGRA_EXT, GL_UNSIGNED_BYTE, bo_data); glPixelStorei(GL_UNPACK_ROW_LENGTH_EXT, 0); - wlr_drm_plane_swap_buffers(renderer, plane); + wlr_drm_surface_swap_buffers(&plane->surf); gbm_bo_unmap(bo, bo_data); - return backend->iface->crtc_set_cursor(backend, crtc, bo); + return drm->iface->crtc_set_cursor(drm, crtc, bo); } -static bool wlr_drm_output_move_cursor(struct wlr_output *_output, +static bool wlr_drm_connector_move_cursor(struct wlr_output *output, int x, int y) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - struct wlr_drm_backend *backend = - wl_container_of(output->renderer, backend, renderer); + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + struct wlr_drm_backend *drm = conn->drm; int width, height, tmp; - wlr_output_effective_resolution(_output, &width, &height); + wlr_output_effective_resolution(output, &width, &height); - switch (_output->transform) { + switch (output->transform) { case WL_OUTPUT_TRANSFORM_NORMAL: // nothing to do break; @@ -706,51 +583,45 @@ static bool wlr_drm_output_move_cursor(struct wlr_output *_output, default: // TODO other transformations wlr_log(L_ERROR, "TODO: handle surface to crtc for transformation = %d", - _output->transform); + output->transform); break; } - return backend->iface->crtc_move_cursor(backend, output->crtc, x, y); + return drm->iface->crtc_move_cursor(drm, conn->crtc, x, y); } -static void wlr_drm_output_destroy(struct wlr_output *_output) { - struct wlr_drm_output *output = (struct wlr_drm_output *)_output; - wlr_drm_output_cleanup(output); - wl_event_source_remove(output->retry_pageflip); - free(output); +static void wlr_drm_connector_destroy(struct wlr_output *output) { + struct wlr_drm_connector *conn = (struct wlr_drm_connector *)output; + wlr_drm_connector_cleanup(conn); + wl_event_source_remove(conn->retry_pageflip); + free(conn); } static struct wlr_output_impl output_impl = { - .enable = wlr_drm_output_enable, - .set_mode = wlr_drm_output_set_mode, - .transform = wlr_drm_output_transform, - .set_cursor = wlr_drm_output_set_cursor, - .move_cursor = wlr_drm_output_move_cursor, - .destroy = wlr_drm_output_destroy, - .make_current = wlr_drm_output_make_current, - .swap_buffers = wlr_drm_output_swap_buffers, - .set_gamma = wlr_drm_output_set_gamma, - .get_gamma_size = wlr_drm_output_get_gamma_size, + .enable = wlr_drm_connector_enable, + .set_mode = wlr_drm_connector_set_mode, + .transform = wlr_drm_connector_transform, + .set_cursor = wlr_drm_connector_set_cursor, + .move_cursor = wlr_drm_connector_move_cursor, + .destroy = wlr_drm_connector_destroy, + .make_current = wlr_drm_connector_make_current, + .swap_buffers = wlr_drm_connector_swap_buffers, + .set_gamma = wlr_drm_connector_set_gamma, + .get_gamma_size = wlr_drm_connector_get_gamma_size, }; static int retry_pageflip(void *data) { - struct wlr_drm_output *output = data; - wlr_log(L_INFO, "%s: Retrying pageflip", output->output.name); - wlr_drm_output_start_renderer(output); + struct wlr_drm_connector *conn = data; + wlr_log(L_INFO, "%s: Retrying pageflip", conn->output.name); + wlr_drm_connector_start_renderer(conn); return 0; } static int find_id(const void *item, const void *cmp_to) { - const struct wlr_drm_output *output = item; + const struct wlr_drm_connector *conn = item; const uint32_t *id = cmp_to; - if (output->connector < *id) { - return -1; - } else if (output->connector > *id) { - return 1; - } else { - return 0; - } + return (int)conn->id - (int)*id; } static const int32_t subpixel_map[] = { @@ -762,126 +633,126 @@ static const int32_t subpixel_map[] = { [DRM_MODE_SUBPIXEL_NONE] = WL_OUTPUT_SUBPIXEL_NONE, }; -void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { +void wlr_drm_scan_connectors(struct wlr_drm_backend *drm) { wlr_log(L_INFO, "Scanning DRM connectors"); - drmModeRes *res = drmModeGetResources(backend->fd); + drmModeRes *res = drmModeGetResources(drm->fd); if (!res) { wlr_log_errno(L_ERROR, "Failed to get DRM resources"); return; } - size_t seen_len = backend->outputs->length; + size_t seen_len = drm->outputs->length; // +1 so it can never be 0 bool seen[seen_len + 1]; memset(seen, 0, sizeof(seen)); for (int i = 0; i < res->count_connectors; ++i) { - drmModeConnector *conn = drmModeGetConnector(backend->fd, + drmModeConnector *drm_conn = drmModeGetConnector(drm->fd, res->connectors[i]); - if (!conn) { + if (!drm_conn) { wlr_log_errno(L_ERROR, "Failed to get DRM connector"); continue; } - struct wlr_drm_output *output; - int index = list_seq_find(backend->outputs, find_id, &conn->connector_id); + struct wlr_drm_connector *wlr_conn; + int index = list_seq_find(drm->outputs, find_id, &drm_conn->connector_id); if (index == -1) { - output = calloc(1, sizeof(*output)); - if (!output) { + wlr_conn = calloc(1, sizeof(*wlr_conn)); + if (!wlr_conn) { wlr_log_errno(L_ERROR, "Allocation failed"); - drmModeFreeConnector(conn); + drmModeFreeConnector(drm_conn); continue; } - wlr_output_init(&output->output, &output_impl); + wlr_output_init(&wlr_conn->output, &output_impl); - struct wl_event_loop *ev = wl_display_get_event_loop(backend->display); - output->retry_pageflip = wl_event_loop_add_timer(ev, retry_pageflip, - output); + struct wl_event_loop *ev = wl_display_get_event_loop(drm->display); + wlr_conn->retry_pageflip = wl_event_loop_add_timer(ev, retry_pageflip, + wlr_conn); - output->renderer = &backend->renderer; - output->state = WLR_DRM_OUTPUT_DISCONNECTED; - output->connector = conn->connector_id; + wlr_conn->drm = drm; + wlr_conn->state = WLR_DRM_CONN_DISCONNECTED; + wlr_conn->id = drm_conn->connector_id; - drmModeEncoder *curr_enc = drmModeGetEncoder(backend->fd, - conn->encoder_id); + drmModeEncoder *curr_enc = drmModeGetEncoder(drm->fd, + drm_conn->encoder_id); if (curr_enc) { - output->old_crtc = drmModeGetCrtc(backend->fd, curr_enc->crtc_id); + wlr_conn->old_crtc = drmModeGetCrtc(drm->fd, curr_enc->crtc_id); drmModeFreeEncoder(curr_enc); } - output->output.phys_width = conn->mmWidth; - output->output.phys_height = conn->mmHeight; - output->output.subpixel = subpixel_map[conn->subpixel]; - snprintf(output->output.name, sizeof(output->output.name), "%s-%"PRIu32, - conn_get_name(conn->connector_type), - conn->connector_type_id); + wlr_conn->output.phys_width = drm_conn->mmWidth; + wlr_conn->output.phys_height = drm_conn->mmHeight; + wlr_conn->output.subpixel = subpixel_map[drm_conn->subpixel]; + snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name), + "%s-%"PRIu32, + conn_get_name(drm_conn->connector_type), + drm_conn->connector_type_id); - wlr_drm_get_connector_props(backend->fd, - output->connector, &output->props); + wlr_drm_get_connector_props(drm->fd, wlr_conn->id, &wlr_conn->props); size_t edid_len = 0; - uint8_t *edid = wlr_drm_get_prop_blob(backend->fd, - output->connector, output->props.edid, &edid_len); - parse_edid(&output->output, edid_len, edid); + uint8_t *edid = wlr_drm_get_prop_blob(drm->fd, + wlr_conn->id, wlr_conn->props.edid, &edid_len); + parse_edid(&wlr_conn->output, edid_len, edid); free(edid); - if (list_add(backend->outputs, output) == -1) { + if (list_add(drm->outputs, wlr_conn) == -1) { wlr_log_errno(L_ERROR, "Allocation failed"); - drmModeFreeConnector(conn); - wl_event_source_remove(output->retry_pageflip); - free(output); + drmModeFreeConnector(drm_conn); + wl_event_source_remove(wlr_conn->retry_pageflip); + free(wlr_conn); continue; } - wlr_output_create_global(&output->output, backend->display); - wlr_log(L_INFO, "Found display '%s'", output->output.name); + wlr_output_create_global(&wlr_conn->output, drm->display); + wlr_log(L_INFO, "Found display '%s'", wlr_conn->output.name); } else { - output = backend->outputs->items[index]; + wlr_conn = drm->outputs->items[index]; seen[index] = true; } - if (output->state == WLR_DRM_OUTPUT_DISCONNECTED && - conn->connection == DRM_MODE_CONNECTED) { + if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED && + drm_conn->connection == DRM_MODE_CONNECTED) { - wlr_log(L_INFO, "'%s' connected", output->output.name); + wlr_log(L_INFO, "'%s' connected", wlr_conn->output.name); wlr_log(L_INFO, "Detected modes:"); - for (int i = 0; i < conn->count_modes; ++i) { - struct wlr_drm_output_mode *mode = calloc(1, - sizeof(struct wlr_drm_output_mode)); + for (int i = 0; i < drm_conn->count_modes; ++i) { + struct wlr_drm_mode *mode = calloc(1, sizeof(*mode)); if (!mode) { wlr_log_errno(L_ERROR, "Allocation failed"); continue; } - mode->mode = conn->modes[i]; - mode->wlr_mode.width = mode->mode.hdisplay; - mode->wlr_mode.height = mode->mode.vdisplay; - mode->wlr_mode.refresh = calculate_refresh_rate(&mode->mode); + mode->drm_mode = drm_conn->modes[i]; + mode->wlr_mode.width = mode->drm_mode.hdisplay; + mode->wlr_mode.height = mode->drm_mode.vdisplay; + mode->wlr_mode.refresh = calculate_refresh_rate(&mode->drm_mode); wlr_log(L_INFO, " %"PRId32"@%"PRId32"@%"PRId32, mode->wlr_mode.width, mode->wlr_mode.height, mode->wlr_mode.refresh); - if (list_add(output->output.modes, mode) == -1) { + if (list_add(wlr_conn->output.modes, mode) == -1) { wlr_log_errno(L_ERROR, "Allocation failed"); free(mode); continue; } } - output->state = WLR_DRM_OUTPUT_NEEDS_MODESET; - wlr_log(L_INFO, "Sending modesetting signal for '%s'", output->output.name); - wl_signal_emit(&backend->backend.events.output_add, &output->output); - } else if (output->state == WLR_DRM_OUTPUT_CONNECTED && - conn->connection != DRM_MODE_CONNECTED) { + wlr_conn->state = WLR_DRM_CONN_NEEDS_MODESET; + wlr_log(L_INFO, "Sending modesetting signal for '%s'", + wlr_conn->output.name); + wl_signal_emit(&drm->backend.events.output_add, &wlr_conn->output); + } else if (wlr_conn->state == WLR_DRM_CONN_CONNECTED && + drm_conn->connection != DRM_MODE_CONNECTED) { - wlr_log(L_INFO, "'%s' disconnected", output->output.name); - wlr_drm_output_cleanup(output); + wlr_log(L_INFO, "'%s' disconnected", wlr_conn->output.name); + wlr_drm_connector_cleanup(wlr_conn); } - drmModeFreeConnector(conn); + drmModeFreeConnector(drm_conn); } drmModeFreeResources(res); @@ -891,38 +762,36 @@ void wlr_drm_scan_connectors(struct wlr_drm_backend *backend) { continue; } - struct wlr_drm_output *output = backend->outputs->items[i]; + struct wlr_drm_connector *conn = drm->outputs->items[i]; - wlr_log(L_INFO, "'%s' disappeared", output->output.name); - wlr_drm_output_cleanup(output); + wlr_log(L_INFO, "'%s' disappeared", conn->output.name); + wlr_drm_connector_cleanup(conn); - drmModeFreeCrtc(output->old_crtc); - wl_event_source_remove(output->retry_pageflip); - free(output); + drmModeFreeCrtc(conn->old_crtc); + wl_event_source_remove(conn->retry_pageflip); + free(conn); - list_del(backend->outputs, i); + list_del(drm->outputs, i); } } static void page_flip_handler(int fd, unsigned seq, unsigned tv_sec, unsigned tv_usec, void *user) { - struct wlr_drm_output *output = user; - struct wlr_drm_backend *backend = - wl_container_of(output->renderer, backend, renderer); + struct wlr_drm_connector *conn = user; + struct wlr_drm_backend *drm = conn->drm; - output->pageflip_pending = false; - if (output->state != WLR_DRM_OUTPUT_CONNECTED) { + conn->pageflip_pending = false; + if (conn->state != WLR_DRM_CONN_CONNECTED) { return; } - struct wlr_drm_plane *plane = output->crtc->primary; - if (plane->front) { - gbm_surface_release_buffer(plane->gbm, plane->front); - plane->front = NULL; + wlr_drm_surface_post(&conn->crtc->primary->surf); + if (drm->parent) { + wlr_drm_surface_post(&conn->crtc->primary->mgpu_surf); } - if (backend->session->active) { - wl_signal_emit(&output->output.events.frame, &output->output); + if (drm->session->active) { + wl_signal_emit(&conn->output.events.frame, &conn->output); } } @@ -940,9 +809,9 @@ void wlr_drm_restore_outputs(struct wlr_drm_backend *drm) { uint64_t to_close = (1 << drm->outputs->length) - 1; for (size_t i = 0; i < drm->outputs->length; ++i) { - struct wlr_drm_output *output = drm->outputs->items[i]; - if (output->state == WLR_DRM_OUTPUT_CONNECTED) { - output->state = WLR_DRM_OUTPUT_CLEANUP; + struct wlr_drm_connector *conn = drm->outputs->items[i]; + if (conn->state == WLR_DRM_CONN_CONNECTED) { + conn->state = WLR_DRM_CONN_CLEANUP; } } @@ -951,8 +820,8 @@ void wlr_drm_restore_outputs(struct wlr_drm_backend *drm) { while (to_close && time(NULL) < timeout) { wlr_drm_event(drm->fd, 0, NULL); for (size_t i = 0; i < drm->outputs->length; ++i) { - struct wlr_drm_output *output = drm->outputs->items[i]; - if (output->state != WLR_DRM_OUTPUT_CLEANUP || !output->pageflip_pending) { + struct wlr_drm_connector *conn = drm->outputs->items[i]; + if (conn->state != WLR_DRM_CONN_CLEANUP || !conn->pageflip_pending) { to_close &= ~(1 << i); } } @@ -963,50 +832,53 @@ void wlr_drm_restore_outputs(struct wlr_drm_backend *drm) { } for (size_t i = 0; i < drm->outputs->length; ++i) { - struct wlr_drm_output *output = drm->outputs->items[i]; - drmModeCrtc *crtc = output->old_crtc; + struct wlr_drm_connector *conn = drm->outputs->items[i]; + drmModeCrtc *crtc = conn->old_crtc; if (!crtc) { continue; } drmModeSetCrtc(drm->fd, crtc->crtc_id, crtc->buffer_id, crtc->x, crtc->y, - &output->connector, 1, &crtc->mode); + &conn->id, 1, &crtc->mode); drmModeFreeCrtc(crtc); } } -void wlr_drm_output_cleanup(struct wlr_drm_output *output) { - if (!output) { +void wlr_drm_connector_cleanup(struct wlr_drm_connector *conn) { + if (!conn) { return; } - struct wlr_drm_renderer *renderer = output->renderer; - struct wlr_drm_backend *backend = - wl_container_of(renderer, backend, renderer); + struct wlr_drm_backend *drm = conn->drm; - switch (output->state) { - case WLR_DRM_OUTPUT_CONNECTED: - case WLR_DRM_OUTPUT_CLEANUP:; - struct wlr_drm_crtc *crtc = output->crtc; + switch (conn->state) { + case WLR_DRM_CONN_CONNECTED: + case WLR_DRM_CONN_CLEANUP:; + struct wlr_drm_crtc *crtc = conn->crtc; for (int i = 0; i < 3; ++i) { - wlr_drm_plane_renderer_free(renderer, crtc->planes[i]); - if (crtc->planes[i] && crtc->planes[i]->id == 0) { + if (!crtc->planes[i]) { + continue; + } + + wlr_drm_surface_finish(&crtc->planes[i]->surf); + wlr_drm_surface_finish(&crtc->planes[i]->mgpu_surf); + if (crtc->planes[i]->id == 0) { free(crtc->planes[i]); crtc->planes[i] = NULL; } } - output->crtc = NULL; - output->possible_crtc = 0; + conn->crtc = NULL; + conn->possible_crtc = 0; /* Fallthrough */ - case WLR_DRM_OUTPUT_NEEDS_MODESET: + case WLR_DRM_CONN_NEEDS_MODESET: wlr_log(L_INFO, "Emmiting destruction signal for '%s'", - output->output.name); - wl_signal_emit(&backend->backend.events.output_remove, &output->output); + conn->output.name); + wl_signal_emit(&drm->backend.events.output_remove, &conn->output); break; - case WLR_DRM_OUTPUT_DISCONNECTED: + case WLR_DRM_CONN_DISCONNECTED: break; } - output->state = WLR_DRM_OUTPUT_DISCONNECTED; + conn->state = WLR_DRM_CONN_DISCONNECTED; } diff --git a/backend/drm/legacy.c b/backend/drm/legacy.c new file mode 100644 index 00000000..d75eb2cb --- /dev/null +++ b/backend/drm/legacy.c @@ -0,0 +1,66 @@ +#include <gbm.h> +#include <xf86drm.h> +#include <xf86drmMode.h> +#include <wlr/util/log.h> +#include "backend/drm/drm.h" +#include "backend/drm/iface.h" +#include "backend/drm/util.h" + +static bool legacy_crtc_pageflip(struct wlr_drm_backend *drm, + struct wlr_drm_connector *conn, struct wlr_drm_crtc *crtc, + uint32_t fb_id, drmModeModeInfo *mode) { + if (mode) { + if (drmModeSetCrtc(drm->fd, crtc->id, fb_id, 0, 0, + &conn->id, 1, mode)) { + wlr_log_errno(L_ERROR, "%s: Failed to set CRTC", conn->output.name); + return false; + } + } + + if (drmModePageFlip(drm->fd, crtc->id, fb_id, DRM_MODE_PAGE_FLIP_EVENT, conn)) { + wlr_log_errno(L_ERROR, "%s: Failed to page flip", conn->output.name); + return false; + } + + return true; +} + +static void legacy_conn_enable(struct wlr_drm_backend *drm, + struct wlr_drm_connector *conn, bool enable) { + drmModeConnectorSetProperty(drm->fd, conn->id, conn->props.dpms, + enable ? DRM_MODE_DPMS_ON : DRM_MODE_DPMS_OFF); +} + +bool legacy_crtc_set_cursor(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc, struct gbm_bo *bo) { + if (!crtc || !crtc->cursor) { + return true; + } + + if (!bo) { + drmModeSetCursor(drm->fd, crtc->id, 0, 0, 0); + return true; + } + + struct wlr_drm_plane *plane = crtc->cursor; + + if (drmModeSetCursor(drm->fd, crtc->id, gbm_bo_get_handle(bo).u32, + plane->surf.width, plane->surf.height)) { + wlr_log_errno(L_ERROR, "Failed to set hardware cursor"); + return false; + } + + return true; +} + +bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm, + struct wlr_drm_crtc *crtc, int x, int y) { + return !drmModeMoveCursor(drm->fd, crtc->id, x, y); +} + +const struct wlr_drm_interface legacy_iface = { + .conn_enable = legacy_conn_enable, + .crtc_pageflip = legacy_crtc_pageflip, + .crtc_set_cursor = legacy_crtc_set_cursor, + .crtc_move_cursor = legacy_crtc_move_cursor, +}; diff --git a/backend/drm/drm-properties.c b/backend/drm/properties.c index ef24476f..5bec3243 100644 --- a/backend/drm/drm-properties.c +++ b/backend/drm/properties.c @@ -5,7 +5,7 @@ #include <xf86drm.h> #include <xf86drmMode.h> #include <wlr/util/log.h> -#include "backend/drm-properties.h" +#include "backend/drm/properties.h" /* * Creates a mapping between property names and an array index where to store diff --git a/backend/drm/renderer.c b/backend/drm/renderer.c new file mode 100644 index 00000000..c5840436 --- /dev/null +++ b/backend/drm/renderer.c @@ -0,0 +1,250 @@ +#include <stdbool.h> +#include <stdlib.h> +#include <unistd.h> + +#include <gbm.h> +#include <GLES2/gl2.h> +#include <EGL/egl.h> +#include <EGL/eglext.h> +#include <wayland-util.h> + +#include <wlr/egl.h> +#include <wlr/util/log.h> +#include <wlr/render/matrix.h> +#include <wlr/render/gles2.h> +#include <wlr/render.h> +#include "backend/drm/drm.h" + +bool wlr_drm_renderer_init(struct wlr_drm_backend *drm, + struct wlr_drm_renderer *renderer) { + renderer->gbm = gbm_create_device(drm->fd); + if (!renderer->gbm) { + wlr_log(L_ERROR, "Failed to create GBM device"); + return false; + } + + if (!wlr_egl_init(&renderer->egl, EGL_PLATFORM_GBM_MESA, + GBM_FORMAT_ARGB8888, renderer->gbm)) { + goto error_gbm; + } + + renderer->wlr_rend = wlr_gles2_renderer_create(&drm->backend); + if (!renderer->wlr_rend) { + wlr_log(L_ERROR, "Failed to create WLR renderer"); + goto error_egl; + } + + renderer->fd = drm->fd; + return true; + +error_egl: + wlr_egl_free(&renderer->egl); +error_gbm: + gbm_device_destroy(renderer->gbm); + return false; +} + +void wlr_drm_renderer_finish(struct wlr_drm_renderer *renderer) { + if (!renderer) { + return; + } + + wlr_renderer_destroy(renderer->wlr_rend); + wlr_egl_free(&renderer->egl); + gbm_device_destroy(renderer->gbm); +} + +bool wlr_drm_surface_init(struct wlr_drm_surface *surf, + struct wlr_drm_renderer *renderer, uint32_t width, uint32_t height, + uint32_t format, uint32_t flags) { + if (surf->width == width && surf->height == height) { + return true; + } + + surf->renderer = renderer; + surf->width = width; + surf->height = height; + + surf->gbm = gbm_surface_create(renderer->gbm, width, height, + format, GBM_BO_USE_RENDERING | flags); + if (!surf->gbm) { + wlr_log_errno(L_ERROR, "Failed to create GBM surface"); + goto error_zero; + } + + surf->egl = wlr_egl_create_surface(&renderer->egl, surf->gbm); + if (surf->egl == EGL_NO_SURFACE) { + wlr_log(L_ERROR, "Failed to create EGL surface"); + goto error_gbm; + } + + return true; + +error_gbm: + gbm_surface_destroy(surf->gbm); +error_zero: + memset(surf, 0, sizeof(*surf)); + return false; +} + +void wlr_drm_surface_finish(struct wlr_drm_surface *surf) { + if (!surf || !surf->renderer) { + return; + } + + eglMakeCurrent(surf->renderer->egl.display, EGL_NO_SURFACE, EGL_NO_SURFACE, + EGL_NO_CONTEXT); + + if (surf->front) { + gbm_surface_release_buffer(surf->gbm, surf->front); + } + if (surf->back) { + gbm_surface_release_buffer(surf->gbm, surf->back); + } + + if (surf->egl) { + eglDestroySurface(surf->renderer->egl.display, surf->egl); + } + if (surf->gbm) { + gbm_surface_destroy(surf->gbm); + } + + memset(surf, 0, sizeof(*surf)); +} + +void wlr_drm_surface_make_current(struct wlr_drm_surface *surf) { + eglMakeCurrent(surf->renderer->egl.display, surf->egl, surf->egl, + surf->renderer->egl.context); +} + +struct gbm_bo *wlr_drm_surface_swap_buffers(struct wlr_drm_surface *surf) { + if (surf->front) { + gbm_surface_release_buffer(surf->gbm, surf->front); + } + + eglSwapBuffers(surf->renderer->egl.display, surf->egl); + + surf->front = surf->back; + surf->back = gbm_surface_lock_front_buffer(surf->gbm); + return surf->back; +} + +struct gbm_bo *wlr_drm_surface_get_front(struct wlr_drm_surface *surf) { + if (surf->front) { + return surf->front; + } + + wlr_drm_surface_make_current(surf); + glViewport(0, 0, surf->width, surf->height); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + return wlr_drm_surface_swap_buffers(surf); +} + +void wlr_drm_surface_post(struct wlr_drm_surface *surf) { + if (surf->front) { + gbm_surface_release_buffer(surf->gbm, surf->front); + surf->front = NULL; + } +} + +struct tex { + struct wlr_egl *egl; + EGLImageKHR img; + struct wlr_texture *tex; +}; + +static void free_eglimage(struct gbm_bo *bo, void *data) { + struct tex *tex = data; + + wlr_egl_destroy_image(tex->egl, tex->img); + wlr_texture_destroy(tex->tex); + free(tex); +} + +static struct wlr_texture *get_tex_for_bo(struct wlr_drm_renderer *renderer, struct gbm_bo *bo) { + struct tex *tex = gbm_bo_get_user_data(bo); + if (tex) { + return tex->tex; + } + + tex = malloc(sizeof(*tex)); + if (!tex) { + wlr_log_errno(L_ERROR, "Allocation failed"); + return NULL; + } + + tex->egl = &renderer->egl; + + int dmabuf_fd = gbm_bo_get_fd(bo); + uint32_t width = gbm_bo_get_width(bo); + uint32_t height = gbm_bo_get_height(bo); + + EGLint attribs[] = { + EGL_WIDTH, width, + EGL_HEIGHT, height, + EGL_LINUX_DRM_FOURCC_EXT, gbm_bo_get_format(bo), + EGL_DMA_BUF_PLANE0_FD_EXT, dmabuf_fd, + EGL_DMA_BUF_PLANE0_OFFSET_EXT, gbm_bo_get_offset(bo, 0), + EGL_DMA_BUF_PLANE0_PITCH_EXT, gbm_bo_get_stride_for_plane(bo, 0), + EGL_IMAGE_PRESERVED_KHR, EGL_FALSE, + EGL_NONE, + }; + + tex->img = renderer->egl.eglCreateImageKHR(renderer->egl.display, EGL_NO_CONTEXT, + EGL_LINUX_DMA_BUF_EXT, NULL, attribs); + if (!tex->img) { + wlr_log(L_ERROR, "Failed to create EGL image: %s", egl_error()); + abort(); + } + + tex->tex = wlr_render_texture_create(renderer->wlr_rend); + wlr_texture_upload_eglimage(tex->tex, tex->img, width, height); + + gbm_bo_set_user_data(bo, tex, free_eglimage); + + return tex->tex; +} + +struct gbm_bo *wlr_drm_surface_mgpu_copy(struct wlr_drm_surface *dest, struct gbm_bo *src) { + wlr_drm_surface_make_current(dest); + + struct wlr_texture *tex = get_tex_for_bo(dest->renderer, src); + + static const float matrix[16] = { + [0] = 2.0f, + [3] = -1.0f, + [5] = 2.0f, + [7] = -1.0f, + [10] = 1.0f, + [15] = 1.0f, + }; + + glViewport(0, 0, dest->width, dest->height); + glClearColor(0.0, 0.0, 0.0, 1.0); + glClear(GL_COLOR_BUFFER_BIT); + wlr_render_with_matrix(dest->renderer->wlr_rend, tex, &matrix); + + return wlr_drm_surface_swap_buffers(dest); +} + +bool wlr_drm_plane_surfaces_init(struct wlr_drm_plane *plane, struct wlr_drm_backend *drm, + int32_t width, uint32_t height, uint32_t format) { + if (!drm->parent) { + return wlr_drm_surface_init(&plane->surf, &drm->renderer, width, height, + format, GBM_BO_USE_SCANOUT); + } + + if (!wlr_drm_surface_init(&plane->surf, &drm->parent->renderer, + width, height, format, GBM_BO_USE_LINEAR)) { + return false; + } + + if (!wlr_drm_surface_init(&plane->mgpu_surf, &drm->renderer, + width, height, format, GBM_BO_USE_SCANOUT)) { + wlr_drm_surface_finish(&plane->surf); + return false; + } + + return true; +} diff --git a/backend/drm/drm-util.c b/backend/drm/util.c index 0f8ee18c..656c070a 100644 --- a/backend/drm/drm-util.c +++ b/backend/drm/util.c @@ -3,7 +3,7 @@ #include <drm.h> #include <drm_mode.h> #include <gbm.h> -#include "backend/drm-util.h" +#include "backend/drm/util.h" #include <wlr/util/log.h> int32_t calculate_refresh_rate(drmModeModeInfo *mode) { diff --git a/backend/meson.build b/backend/meson.build index 9e3b6fed..c5c73288 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -3,12 +3,13 @@ backend_files = files( 'session/direct-ipc.c', 'session/direct.c', 'session/session.c', + 'drm/atomic.c', 'drm/backend.c', 'drm/drm.c', - 'drm/drm-atomic.c', - 'drm/drm-legacy.c', - 'drm/drm-properties.c', - 'drm/drm-util.c', + 'drm/legacy.c', + 'drm/properties.c', + 'drm/renderer.c', + 'drm/util.c', 'libinput/backend.c', 'libinput/events.c', 'libinput/keyboard.c', diff --git a/backend/session/session.c b/backend/session/session.c index cfa617f6..b73952fd 100644 --- a/backend/session/session.c +++ b/backend/session/session.c @@ -1,7 +1,8 @@ +#define _POSIX_C_SOURCE 200809L #include <assert.h> #include <stddef.h> -#include <stdarg.h> #include <stdlib.h> +#include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <libudev.h> @@ -191,18 +192,16 @@ bool wlr_session_change_vt(struct wlr_session *session, unsigned vt) { /* Tests if 'path' is KMS compatible by trying to open it. * It leaves the open device in *fd_out it it succeeds. */ -static bool device_is_kms(struct wlr_session *restrict session, - const char *restrict path, int *restrict fd_out) { - +static int open_if_kms(struct wlr_session *restrict session, const char *restrict path) { int fd; if (!path) { - return false; + return -1; } fd = wlr_session_open_file(session, path); if (fd < 0) { - return false; + return -1; } drmModeRes *res = drmModeGetResources(fd); @@ -216,26 +215,54 @@ static bool device_is_kms(struct wlr_session *restrict session, goto out_res; } - if (*fd_out >= 0) { - wlr_session_close_file(session, *fd_out); - } - - *fd_out = fd; - drmModeFreeResources(res); - return true; + return fd; out_res: drmModeFreeResources(res); out_fd: wlr_session_close_file(session, fd); - return false; + return -1; +} + +static size_t explicit_find_gpus(struct wlr_session *session, + size_t ret_len, int ret[static ret_len], const char *str) { + char *gpus = strdup(str); + if (!gpus) { + wlr_log_errno(L_ERROR, "Allocation failed"); + return 0; + } + + size_t i = 0; + char *save; + char *ptr = strtok_r(gpus, ":", &save); + do { + if (i >= ret_len) { + break; + } + + ret[i] = open_if_kms(session, ptr); + if (ret[i] < 0) { + wlr_log(L_ERROR, "Unable to open %s as DRM device", ptr); + } else { + ++i; + } + } while ((ptr = strtok_r(NULL, ":", &save))); + + free(ptr); + return i; } /* Tries to find the primary GPU by checking for the "boot_vga" attribute. * If it's not found, it returns the first valid GPU it finds. */ -int wlr_session_find_gpu(struct wlr_session *session) { +size_t wlr_session_find_gpus(struct wlr_session *session, + size_t ret_len, int ret[static ret_len]) { + const char *explicit = getenv("WLR_DRM_DEVICES"); + if (explicit) { + return explicit_find_gpus(session, ret_len, ret, explicit); + } + struct udev_enumerate *en = udev_enumerate_new(session->udev); if (!en) { wlr_log(L_ERROR, "Failed to create udev enumeration"); @@ -247,9 +274,13 @@ int wlr_session_find_gpu(struct wlr_session *session) { udev_enumerate_scan_devices(en); struct udev_list_entry *entry; - int fd = -1; + size_t i = 0; udev_list_entry_foreach(entry, udev_enumerate_get_list_entry(en)) { + if (i == ret_len) { + break; + } + bool is_boot_vga = false; const char *path = udev_list_entry_get_name(entry); @@ -258,15 +289,13 @@ int wlr_session_find_gpu(struct wlr_session *session) { continue; } - /* const char *seat = udev_device_get_property_value(dev, "ID_SEAT"); if (!seat) seat = "seat0"; - if (strcmp(session->seat, seat) != 0) { + if (session->seat[0] && strcmp(session->seat, seat) != 0) { udev_device_unref(dev); continue; } - */ // This is owned by 'dev', so we don't need to free it struct udev_device *pci = @@ -279,27 +308,25 @@ int wlr_session_find_gpu(struct wlr_session *session) { } } - // We already have a valid GPU - if (!is_boot_vga && fd >= 0) { - udev_device_unref(dev); - continue; - } - - path = udev_device_get_devnode(dev); - if (!device_is_kms(session, path, &fd)) { + int fd = open_if_kms(session, udev_device_get_devnode(dev)); + if (fd < 0) { udev_device_unref(dev); continue; } udev_device_unref(dev); - // We've found the primary GPU + ret[i] = fd; if (is_boot_vga) { - break; + int tmp = ret[0]; + ret[0] = ret[i]; + ret[i] = tmp; } + + ++i; } udev_enumerate_unref(en); - return fd; + return i; } |