From 610b0493ac4a3bbde44378adf855c7202b1e59c4 Mon Sep 17 00:00:00 2001 From: Scott Anderson Date: Sat, 30 Sep 2017 19:03:34 +1300 Subject: Rename files to remove pointless drm prefix --- backend/drm/backend.c | 2 +- backend/drm/drm-atomic.c | 188 ------------------------ backend/drm/drm-legacy.c | 65 --------- backend/drm/drm-properties.c | 145 ------------------- backend/drm/drm-util.c | 303 --------------------------------------- backend/drm/drm.c | 14 +- backend/drm/iface_atomic.c | 188 ++++++++++++++++++++++++ backend/drm/iface_legacy.c | 65 +++++++++ backend/drm/properties.c | 145 +++++++++++++++++++ backend/drm/util.c | 303 +++++++++++++++++++++++++++++++++++++++ backend/meson.build | 8 +- include/backend/drm-properties.h | 67 --------- include/backend/drm-util.h | 39 ----- include/backend/drm.h | 186 ------------------------ include/backend/drm/drm.h | 186 ++++++++++++++++++++++++ include/backend/drm/properties.h | 67 +++++++++ include/backend/drm/util.h | 39 +++++ 17 files changed, 1005 insertions(+), 1005 deletions(-) delete mode 100644 backend/drm/drm-atomic.c delete mode 100644 backend/drm/drm-legacy.c delete mode 100644 backend/drm/drm-properties.c delete mode 100644 backend/drm/drm-util.c create mode 100644 backend/drm/iface_atomic.c create mode 100644 backend/drm/iface_legacy.c create mode 100644 backend/drm/properties.c create mode 100644 backend/drm/util.c delete mode 100644 include/backend/drm-properties.h delete mode 100644 include/backend/drm-util.h delete mode 100644 include/backend/drm.h create mode 100644 include/backend/drm/drm.h create mode 100644 include/backend/drm/properties.h create mode 100644 include/backend/drm/util.h diff --git a/backend/drm/backend.c b/backend/drm/backend.c index c394ed65..e046cea6 100644 --- a/backend/drm/backend.c +++ b/backend/drm/backend.c @@ -12,7 +12,7 @@ #include #include #include -#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; diff --git a/backend/drm/drm-atomic.c b/backend/drm/drm-atomic.c deleted file mode 100644 index 16c9c5c3..00000000 --- a/backend/drm/drm-atomic.c +++ /dev/null @@ -1,188 +0,0 @@ -#include -#include -#include -#include -#include "backend/drm.h" -#include "backend/drm-util.h" - -struct atomic { - drmModeAtomicReq *req; - int cursor; - bool failed; -}; - -static void atomic_begin(struct wlr_drm_crtc *crtc, struct atomic *atom) { - if (!crtc->atomic) { - crtc->atomic = drmModeAtomicAlloc(); - if (!crtc->atomic) { - wlr_log_errno(L_ERROR, "Allocation failed"); - atom->failed = true; - return; - } - } - - atom->req = crtc->atomic; - atom->cursor = drmModeAtomicGetCursor(atom->req); - atom->failed = false; -} - -static bool atomic_end(int drm_fd, struct atomic *atom) { - if (atom->failed) { - return false; - } - - uint32_t flags = DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK; - - if (drmModeAtomicCommit(drm_fd, atom->req, flags, NULL)) { - wlr_log_errno(L_ERROR, "Atomic test failed"); - drmModeAtomicSetCursor(atom->req, atom->cursor); - return false; - } - - return true; -} - -static bool atomic_commit(int drm_fd, struct atomic *atom, - struct wlr_drm_output *output, 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); - if (ret) { - wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", - output->output.name, modeset ? "modeset" : "pageflip"); - - // Try to commit without new changes - drmModeAtomicSetCursor(atom->req, atom->cursor); - if (drmModeAtomicCommit(drm_fd, atom->req, flags, output)) { - wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", - output->output.name, modeset ? "modeset" : "pageflip"); - } - } - - drmModeAtomicSetCursor(atom->req, 0); - - return !ret; -} - -static inline void atomic_add(struct atomic *atom, uint32_t id, uint32_t prop, uint64_t val) { - if (!atom->failed && drmModeAtomicAddProperty(atom->req, id, prop, val) < 0) { - wlr_log_errno(L_ERROR, "Failed to add atomic DRM property"); - atom->failed = true; - } -} - -static void set_plane_props(struct atomic *atom, struct wlr_drm_plane *plane, - uint32_t crtc_id, uint32_t fb_id, bool set_crtc_xy) { - uint32_t id = plane->id; - const union wlr_drm_plane_props *props = &plane->props; - - // 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->fb_id, fb_id); - atomic_add(atom, id, props->crtc_id, crtc_id); - if (set_crtc_xy) { - atomic_add(atom, id, props->crtc_x, 0); - atomic_add(atom, id, props->crtc_y, 0); - } -} - -static bool atomic_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 (crtc->mode_id) { - drmModeDestroyPropertyBlob(backend->fd, crtc->mode_id); - } - - if (drmModeCreatePropertyBlob(backend->fd, mode, sizeof(*mode), &crtc->mode_id)) { - wlr_log_errno(L_ERROR, "Unable to create property blob"); - return false; - } - } - - struct atomic atom; - - atomic_begin(crtc, &atom); - atomic_add(&atom, output->connector, output->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, - 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; - struct atomic atom; - - atomic_begin(crtc, &atom); - atomic_add(&atom, crtc->id, crtc->props.active, enable); - atomic_end(backend->fd, &atom); -} - -bool legacy_crtc_set_cursor(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, struct gbm_bo *bo); - -static bool atomic_crtc_set_cursor(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, struct gbm_bo *bo) { - if (!crtc || !crtc->cursor) { - return true; - } - - 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); - } - - struct atomic atom; - - atomic_begin(crtc, &atom); - - if (bo) { - set_plane_props(&atom, plane, crtc->id, get_fb_for_bo(bo), false); - } else { - atomic_add(&atom, plane->id, plane->props.fb_id, 0); - atomic_add(&atom, plane->id, plane->props.crtc_id, 0); - } - - return atomic_end(backend->fd, &atom); -} - -bool legacy_crtc_move_cursor(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, int x, int y); - -static bool atomic_crtc_move_cursor(struct wlr_drm_backend *backend, - 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); - } - - struct atomic atom; - - 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); -} - -const struct wlr_drm_interface atomic_iface = { - .conn_enable = atomic_conn_enable, - .crtc_pageflip = atomic_crtc_pageflip, - .crtc_set_cursor = atomic_crtc_set_cursor, - .crtc_move_cursor = atomic_crtc_move_cursor, -}; 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 -#include -#include -#include -#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-properties.c b/backend/drm/drm-properties.c deleted file mode 100644 index ef24476f..00000000 --- a/backend/drm/drm-properties.c +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include "backend/drm-properties.h" - -/* - * Creates a mapping between property names and an array index where to store - * the ids. The prop_info arrays must be sorted by name, as bsearch is used to - * search them. - */ -struct prop_info { - const char *name; - size_t index; -}; - -static const struct prop_info connector_info[] = { -#define INDEX(name) (offsetof(union wlr_drm_connector_props, name) / sizeof(uint32_t)) - { "CRTC_ID", INDEX(crtc_id) }, - { "DPMS", INDEX(dpms) }, - { "EDID", INDEX(edid) }, -#undef INDEX -}; - -static const struct prop_info crtc_info[] = { -#define INDEX(name) (offsetof(union wlr_drm_crtc_props, name) / sizeof(uint32_t)) - { "ACTIVE", INDEX(active) }, - { "MODE_ID", INDEX(mode_id) }, - { "rotation", INDEX(rotation) }, - { "scaling mode", INDEX(scaling_mode) }, -#undef INDEX -}; - -static const struct prop_info plane_info[] = { -#define INDEX(name) (offsetof(union wlr_drm_plane_props, name) / sizeof(uint32_t)) - { "CRTC_H", INDEX(crtc_h) }, - { "CRTC_ID", INDEX(crtc_id) }, - { "CRTC_W", INDEX(crtc_w) }, - { "CRTC_X", INDEX(crtc_x) }, - { "CRTC_Y", INDEX(crtc_y) }, - { "FB_ID", INDEX(fb_id) }, - { "SRC_H", INDEX(src_h) }, - { "SRC_W", INDEX(src_w) }, - { "SRC_X", INDEX(src_x) }, - { "SRC_Y", INDEX(src_y) }, - { "type", INDEX(type) }, -#undef INDEX -}; - -static int cmp_prop_info(const void *arg1, const void *arg2) { - const char *key = arg1; - const struct prop_info *elem = arg2; - - return strcmp(key, elem->name); -} - -static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result, - const struct prop_info *info, size_t info_len) { - drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type); - if (!props) { - wlr_log_errno(L_ERROR, "Failed to get DRM object properties"); - return false; - } - - for (uint32_t i = 0; i < props->count_props; ++i) { - drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]); - if (!prop) { - wlr_log_errno(L_ERROR, "Failed to get DRM object property"); - continue; - } - - const struct prop_info *p = - bsearch(prop->name, info, info_len, sizeof(info[0]), cmp_prop_info); - if (p) { - result[p->index] = prop->prop_id; - } - - drmModeFreeProperty(prop); - } - - drmModeFreeObjectProperties(props); - return true; -} - -bool wlr_drm_get_connector_props(int fd, uint32_t id, union wlr_drm_connector_props *out) { - return scan_properties(fd, id, DRM_MODE_OBJECT_CONNECTOR, out->props, - connector_info, sizeof(connector_info) / sizeof(connector_info[0])); -} - -bool wlr_drm_get_crtc_props(int fd, uint32_t id, union wlr_drm_crtc_props *out) { - return scan_properties(fd, id, DRM_MODE_OBJECT_CRTC, out->props, - crtc_info, sizeof(crtc_info) / sizeof(crtc_info[0])); -} - -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-util.c b/backend/drm/drm-util.c deleted file mode 100644 index 0f8ee18c..00000000 --- a/backend/drm/drm-util.c +++ /dev/null @@ -1,303 +0,0 @@ -#include -#include -#include -#include -#include -#include "backend/drm-util.h" -#include - -int32_t calculate_refresh_rate(drmModeModeInfo *mode) { - int32_t refresh = (mode->clock * 1000000LL / mode->htotal + - mode->vtotal / 2) / mode->vtotal; - - if (mode->flags & DRM_MODE_FLAG_INTERLACE) { - refresh *= 2; - } - - if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { - refresh /= 2; - } - - if (mode->vscan > 1) { - refresh /= mode->vscan; - } - - return refresh; -} - -// Constructed from http://edid.tv/manufacturer -static const char *get_manufacturer(uint16_t id) { -#define ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f) - switch (id) { - case ID('A', 'A', 'A'): return "Avolites Ltd"; - case ID('A', 'C', 'I'): return "Ancor Communications Inc"; - case ID('A', 'C', 'R'): return "Acer Technologies"; - case ID('A', 'P', 'P'): return "Apple Computer Inc"; - case ID('B', 'N', 'O'): return "Bang & Olufsen"; - case ID('C', 'M', 'N'): return "Chimei Innolux Corporation"; - case ID('C', 'M', 'O'): return "Chi Mei Optoelectronics corp."; - case ID('C', 'R', 'O'): return "Extraordinary Technologies PTY Limited"; - case ID('D', 'E', 'L'): return "Dell Inc."; - case ID('D', 'O', 'N'): return "DENON, Ltd."; - case ID('E', 'N', 'C'): return "Eizo Nanao Corporation"; - case ID('E', 'P', 'H'): return "Epiphan Systems Inc."; - case ID('F', 'U', 'S'): return "Fujitsu Siemens Computers GmbH"; - case ID('G', 'S', 'M'): return "Goldstar Company Ltd"; - case ID('H', 'I', 'Q'): return "Kaohsiung Opto Electronics Americas, Inc."; - case ID('H', 'S', 'D'): return "HannStar Display Corp"; - case ID('H', 'W', 'P'): return "Hewlett Packard"; - case ID('I', 'N', 'T'): return "Interphase Corporation"; - case ID('I', 'V', 'M'): return "Iiyama North America"; - case ID('L', 'E', 'N'): return "Lenovo Group Limited"; - case ID('M', 'A', 'X'): return "Rogen Tech Distribution Inc"; - case ID('M', 'E', 'G'): return "Abeam Tech Ltd"; - case ID('M', 'E', 'I'): return "Panasonic Industry Company"; - case ID('M', 'T', 'C'): return "Mars-Tech Corporation"; - case ID('M', 'T', 'X'): return "Matrox"; - case ID('N', 'E', 'C'): return "NEC Corporation"; - case ID('O', 'N', 'K'): return "ONKYO Corporation"; - case ID('O', 'R', 'N'): return "ORION ELECTRIC CO., LTD."; - case ID('O', 'T', 'M'): return "Optoma Corporation"; - case ID('O', 'V', 'R'): return "Oculus VR, Inc."; - case ID('P', 'H', 'L'): return "Philips Consumer Electronics Company"; - case ID('P', 'I', 'O'): return "Pioneer Electronic Corporation"; - case ID('P', 'N', 'R'): return "Planar Systems, Inc."; - case ID('Q', 'D', 'S'): return "Quanta Display Inc."; - case ID('S', 'A', 'M'): return "Samsung Electric Company"; - case ID('S', 'E', 'C'): return "Seiko Epson Corporation"; - case ID('S', 'H', 'P'): return "Sharp Corporation"; - case ID('S', 'I', 'I'): return "Silicon Image, Inc."; - case ID('S', 'N', 'Y'): return "Sony"; - case ID('T', 'O', 'P'): return "Orion Communications Co., Ltd."; - case ID('T', 'S', 'B'): return "Toshiba America Info Systems Inc"; - case ID('T', 'S', 'T'): return "Transtream Inc"; - case ID('U', 'N', 'K'): return "Unknown"; - case ID('V', 'I', 'Z'): return "VIZIO, Inc"; - case ID('V', 'S', 'C'): return "ViewSonic Corporation"; - case ID('Y', 'M', 'H'): return "Yamaha Corporation"; - default: return "Unknown"; - } -#undef ID -} - -/* See https://en.wikipedia.org/wiki/Extended_Display_Identification_Data for layout of EDID data. - * We don't parse the EDID properly. We just expect to receive valid data. - */ -void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *data) { - if (!data || len < 128) { - snprintf(output->make, sizeof(output->make), ""); - snprintf(output->model, sizeof(output->model), ""); - return; - } - - uint16_t id = (data[8] << 8) | data[9]; - snprintf(output->make, sizeof(output->make), "%s", get_manufacturer(id)); - - output->phys_width = ((data[68] & 0xf0) << 4) | data[66]; - output->phys_height = ((data[68] & 0x0f) << 8) | data[67]; - - for (size_t i = 72; i <= 108; i += 18) { - uint16_t flag = (data[i] << 8) | data[i + 1]; - if (flag == 0 && data[i + 3] == 0xFC) { - sprintf(output->model, "%.13s", &data[i + 5]); - - // Monitor names are terminated by newline if they're too short - char *nl = strchr(output->model, '\n'); - if (nl) { - *nl = '\0'; - } - - break; - } - } -} - -const char *conn_get_name(uint32_t type_id) { - switch (type_id) { - case DRM_MODE_CONNECTOR_Unknown: return "Unknown"; - case DRM_MODE_CONNECTOR_VGA: return "VGA"; - case DRM_MODE_CONNECTOR_DVII: return "DVI-I"; - case DRM_MODE_CONNECTOR_DVID: return "DVI-D"; - case DRM_MODE_CONNECTOR_DVIA: return "DVI-A"; - case DRM_MODE_CONNECTOR_Composite: return "Composite"; - case DRM_MODE_CONNECTOR_SVIDEO: return "SVIDEO"; - case DRM_MODE_CONNECTOR_LVDS: return "LVDS"; - case DRM_MODE_CONNECTOR_Component: return "Component"; - case DRM_MODE_CONNECTOR_9PinDIN: return "DIN"; - case DRM_MODE_CONNECTOR_DisplayPort: return "DP"; - case DRM_MODE_CONNECTOR_HDMIA: return "HDMI-A"; - case DRM_MODE_CONNECTOR_HDMIB: return "HDMI-B"; - case DRM_MODE_CONNECTOR_TV: return "TV"; - case DRM_MODE_CONNECTOR_eDP: return "eDP"; - case DRM_MODE_CONNECTOR_VIRTUAL: return "Virtual"; - case DRM_MODE_CONNECTOR_DSI: return "DSI"; - default: return "Unknown"; - } -} - -static void free_fb(struct gbm_bo *bo, void *data) { - uint32_t id = (uintptr_t)data; - - if (id) { - struct gbm_device *gbm = gbm_bo_get_device(bo); - drmModeRmFB(gbm_device_get_fd(gbm), id); - } -} - -uint32_t get_fb_for_bo(struct gbm_bo *bo) { - uint32_t id = (uintptr_t)gbm_bo_get_user_data(bo); - if (id) { - return id; - } - - struct gbm_device *gbm = gbm_bo_get_device(bo); - - int fd = gbm_device_get_fd(gbm); - uint32_t width = gbm_bo_get_width(bo); - uint32_t height = gbm_bo_get_height(bo); - uint32_t handles[4] = {gbm_bo_get_handle(bo).u32}; - uint32_t pitches[4] = {gbm_bo_get_stride(bo)}; - uint32_t offsets[4] = {gbm_bo_get_offset(bo, 0)}; - uint32_t format = gbm_bo_get_format(bo); - - if (drmModeAddFB2(fd, width, height, format, handles, pitches, offsets, &id, 0)) { - wlr_log_errno(L_ERROR, "Unable to add DRM framebuffer"); - } - - gbm_bo_set_user_data(bo, (void *)(uintptr_t)id, free_fb); - - return id; -} - -static inline bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) { - for (size_t i = 0; i < n; ++i) { - if (arr[i] == key) { - return true; - } - } - return false; -} - -/* - * Store all of the non-recursive state in a struct, so we aren't literally - * passing 12 arguments to a function. - */ -struct match_state { - const size_t num_objs; - const uint32_t *restrict objs; - const size_t num_res; - size_t score; - size_t replaced; - uint32_t *restrict res; - uint32_t *restrict best; - const uint32_t *restrict orig; - bool exit_early; -}; - -/* - * skips: The number of SKIP elements encountered so far. - * score: The number of resources we've matched so far. - * replaced: The number of changes from the original solution. - * i: The index of the current element. - * - * This tries to match a solution as close to st->orig as it can. - * - * Returns whether we've set a new best element with this solution. - */ -static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_t replaced, size_t i) { - // Finished - if (i >= st->num_res) { - if (score > st->score || (score == st->score && replaced < st->replaced)) { - st->score = score; - st->replaced = replaced; - memcpy(st->best, st->res, sizeof st->best[0] * st->num_res); - - if (st->score == st->num_objs && st->replaced == 0) { - st->exit_early = true; - } - st->exit_early = (st->score == st->num_res - skips - || st->score == st->num_objs) - && st->replaced == 0; - - return true; - } else { - return false; - } - } - - if (st->orig[i] == SKIP) { - st->res[i] = SKIP; - return match_obj_(st, skips + 1, score, replaced, i + 1); - } - - /* - * Attempt to use the current solution first, to try and avoid - * recalculating everything - */ - - if (st->orig[i] != UNMATCHED && !is_taken(i, st->res, st->orig[i])) { - st->res[i] = st->orig[i]; - if (match_obj_(st, skips, score + 1, replaced, i + 1)) { - return true; - } - } - - if (st->orig[i] != UNMATCHED) { - ++replaced; - } - - bool is_best = false; - for (st->res[i] = 0; st->res[i] < st->num_objs; ++st->res[i]) { - // We tried this earlier - if (st->res[i] == st->orig[i]) { - continue; - } - - // Not compatable - if (!(st->objs[st->res[i]] & (1 << i))) { - continue; - } - - // Already taken - if (is_taken(i, st->res, st->res[i])) { - continue; - } - - if (match_obj_(st, skips, score + 1, replaced, i + 1)) { - is_best = true; - } - - if (st->exit_early) { - return true; - } - } - - if (is_best) { - return true; - } - - // Maybe this resource can't be matched - st->res[i] = UNMATCHED; - return match_obj_(st, skips, score, replaced, i + 1); -} - -size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], - size_t num_res, const uint32_t res[static restrict num_res], - uint32_t out[static restrict num_res]) { - uint32_t solution[num_res]; - - struct match_state st = { - .num_objs = num_objs, - .num_res = num_res, - .score = 0, - .replaced = SIZE_MAX, - .objs = objs, - .res = solution, - .best = out, - .orig = res, - .exit_early = false, - }; - - match_obj_(&st, 0, 0, 0, 0); - return st.score; -} diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 1a656172..cba41023 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -20,12 +20,12 @@ #include #include #include -#include "backend/drm.h" -#include "backend/drm-util.h" +#include "backend/drm/drm.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; + extern const struct wlr_drm_interface iface_legacy; + extern const struct wlr_drm_interface iface_atomic; if (drmSetClientCap(backend->fd, DRM_CLIENT_CAP_UNIVERSAL_PLANES, 1)) { wlr_log(L_ERROR, "DRM universal planes unsupported"); @@ -34,13 +34,13 @@ bool wlr_drm_check_features(struct wlr_drm_backend *backend) { if (getenv("WLR_DRM_NO_ATOMIC")) { wlr_log(L_DEBUG, "WLR_DRM_NO_ATOMIC set, forcing legacy DRM interface"); - backend->iface = &legacy_iface; + backend->iface = &iface_legacy; } else if (drmSetClientCap(backend->fd, DRM_CLIENT_CAP_ATOMIC, 1)) { wlr_log(L_DEBUG, "Atomic modesetting unsupported, using legacy DRM interface"); - backend->iface = &legacy_iface; + backend->iface = &iface_legacy; } else { wlr_log(L_DEBUG, "Using atomic DRM interface"); - backend->iface = &atomic_iface; + backend->iface = &iface_atomic; } return true; diff --git a/backend/drm/iface_atomic.c b/backend/drm/iface_atomic.c new file mode 100644 index 00000000..5bb2da9b --- /dev/null +++ b/backend/drm/iface_atomic.c @@ -0,0 +1,188 @@ +#include +#include +#include +#include +#include "backend/drm/drm.h" +#include "backend/drm/util.h" + +struct atomic { + drmModeAtomicReq *req; + int cursor; + bool failed; +}; + +static void atomic_begin(struct wlr_drm_crtc *crtc, struct atomic *atom) { + if (!crtc->atomic) { + crtc->atomic = drmModeAtomicAlloc(); + if (!crtc->atomic) { + wlr_log_errno(L_ERROR, "Allocation failed"); + atom->failed = true; + return; + } + } + + atom->req = crtc->atomic; + atom->cursor = drmModeAtomicGetCursor(atom->req); + atom->failed = false; +} + +static bool atomic_end(int drm_fd, struct atomic *atom) { + if (atom->failed) { + return false; + } + + uint32_t flags = DRM_MODE_ATOMIC_TEST_ONLY | DRM_MODE_ATOMIC_NONBLOCK; + + if (drmModeAtomicCommit(drm_fd, atom->req, flags, NULL)) { + wlr_log_errno(L_ERROR, "Atomic test failed"); + drmModeAtomicSetCursor(atom->req, atom->cursor); + return false; + } + + return true; +} + +static bool atomic_commit(int drm_fd, struct atomic *atom, + struct wlr_drm_output *output, 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); + if (ret) { + wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", + output->output.name, modeset ? "modeset" : "pageflip"); + + // Try to commit without new changes + drmModeAtomicSetCursor(atom->req, atom->cursor); + if (drmModeAtomicCommit(drm_fd, atom->req, flags, output)) { + wlr_log_errno(L_ERROR, "%s: Atomic commit failed (%s)", + output->output.name, modeset ? "modeset" : "pageflip"); + } + } + + drmModeAtomicSetCursor(atom->req, 0); + + return !ret; +} + +static inline void atomic_add(struct atomic *atom, uint32_t id, uint32_t prop, uint64_t val) { + if (!atom->failed && drmModeAtomicAddProperty(atom->req, id, prop, val) < 0) { + wlr_log_errno(L_ERROR, "Failed to add atomic DRM property"); + atom->failed = true; + } +} + +static void set_plane_props(struct atomic *atom, struct wlr_drm_plane *plane, + uint32_t crtc_id, uint32_t fb_id, bool set_crtc_xy) { + uint32_t id = plane->id; + const union wlr_drm_plane_props *props = &plane->props; + + // 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->fb_id, fb_id); + atomic_add(atom, id, props->crtc_id, crtc_id); + if (set_crtc_xy) { + atomic_add(atom, id, props->crtc_x, 0); + atomic_add(atom, id, props->crtc_y, 0); + } +} + +static bool atomic_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 (crtc->mode_id) { + drmModeDestroyPropertyBlob(backend->fd, crtc->mode_id); + } + + if (drmModeCreatePropertyBlob(backend->fd, mode, sizeof(*mode), &crtc->mode_id)) { + wlr_log_errno(L_ERROR, "Unable to create property blob"); + return false; + } + } + + struct atomic atom; + + atomic_begin(crtc, &atom); + atomic_add(&atom, output->connector, output->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, + 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; + struct atomic atom; + + atomic_begin(crtc, &atom); + atomic_add(&atom, crtc->id, crtc->props.active, enable); + atomic_end(backend->fd, &atom); +} + +bool legacy_crtc_set_cursor(struct wlr_drm_backend *backend, + struct wlr_drm_crtc *crtc, struct gbm_bo *bo); + +static bool atomic_crtc_set_cursor(struct wlr_drm_backend *backend, + struct wlr_drm_crtc *crtc, struct gbm_bo *bo) { + if (!crtc || !crtc->cursor) { + return true; + } + + 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); + } + + struct atomic atom; + + atomic_begin(crtc, &atom); + + if (bo) { + set_plane_props(&atom, plane, crtc->id, get_fb_for_bo(bo), false); + } else { + atomic_add(&atom, plane->id, plane->props.fb_id, 0); + atomic_add(&atom, plane->id, plane->props.crtc_id, 0); + } + + return atomic_end(backend->fd, &atom); +} + +bool legacy_crtc_move_cursor(struct wlr_drm_backend *backend, + struct wlr_drm_crtc *crtc, int x, int y); + +static bool atomic_crtc_move_cursor(struct wlr_drm_backend *backend, + 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); + } + + struct atomic atom; + + 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); +} + +const struct wlr_drm_interface iface_atomic = { + .conn_enable = atomic_conn_enable, + .crtc_pageflip = atomic_crtc_pageflip, + .crtc_set_cursor = atomic_crtc_set_cursor, + .crtc_move_cursor = atomic_crtc_move_cursor, +}; diff --git a/backend/drm/iface_legacy.c b/backend/drm/iface_legacy.c new file mode 100644 index 00000000..856e9060 --- /dev/null +++ b/backend/drm/iface_legacy.c @@ -0,0 +1,65 @@ +#include +#include +#include +#include +#include "backend/drm/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 iface_legacy = { + .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/properties.c b/backend/drm/properties.c new file mode 100644 index 00000000..5bec3243 --- /dev/null +++ b/backend/drm/properties.c @@ -0,0 +1,145 @@ +#include +#include +#include +#include +#include +#include +#include +#include "backend/drm/properties.h" + +/* + * Creates a mapping between property names and an array index where to store + * the ids. The prop_info arrays must be sorted by name, as bsearch is used to + * search them. + */ +struct prop_info { + const char *name; + size_t index; +}; + +static const struct prop_info connector_info[] = { +#define INDEX(name) (offsetof(union wlr_drm_connector_props, name) / sizeof(uint32_t)) + { "CRTC_ID", INDEX(crtc_id) }, + { "DPMS", INDEX(dpms) }, + { "EDID", INDEX(edid) }, +#undef INDEX +}; + +static const struct prop_info crtc_info[] = { +#define INDEX(name) (offsetof(union wlr_drm_crtc_props, name) / sizeof(uint32_t)) + { "ACTIVE", INDEX(active) }, + { "MODE_ID", INDEX(mode_id) }, + { "rotation", INDEX(rotation) }, + { "scaling mode", INDEX(scaling_mode) }, +#undef INDEX +}; + +static const struct prop_info plane_info[] = { +#define INDEX(name) (offsetof(union wlr_drm_plane_props, name) / sizeof(uint32_t)) + { "CRTC_H", INDEX(crtc_h) }, + { "CRTC_ID", INDEX(crtc_id) }, + { "CRTC_W", INDEX(crtc_w) }, + { "CRTC_X", INDEX(crtc_x) }, + { "CRTC_Y", INDEX(crtc_y) }, + { "FB_ID", INDEX(fb_id) }, + { "SRC_H", INDEX(src_h) }, + { "SRC_W", INDEX(src_w) }, + { "SRC_X", INDEX(src_x) }, + { "SRC_Y", INDEX(src_y) }, + { "type", INDEX(type) }, +#undef INDEX +}; + +static int cmp_prop_info(const void *arg1, const void *arg2) { + const char *key = arg1; + const struct prop_info *elem = arg2; + + return strcmp(key, elem->name); +} + +static bool scan_properties(int fd, uint32_t id, uint32_t type, uint32_t *result, + const struct prop_info *info, size_t info_len) { + drmModeObjectProperties *props = drmModeObjectGetProperties(fd, id, type); + if (!props) { + wlr_log_errno(L_ERROR, "Failed to get DRM object properties"); + return false; + } + + for (uint32_t i = 0; i < props->count_props; ++i) { + drmModePropertyRes *prop = drmModeGetProperty(fd, props->props[i]); + if (!prop) { + wlr_log_errno(L_ERROR, "Failed to get DRM object property"); + continue; + } + + const struct prop_info *p = + bsearch(prop->name, info, info_len, sizeof(info[0]), cmp_prop_info); + if (p) { + result[p->index] = prop->prop_id; + } + + drmModeFreeProperty(prop); + } + + drmModeFreeObjectProperties(props); + return true; +} + +bool wlr_drm_get_connector_props(int fd, uint32_t id, union wlr_drm_connector_props *out) { + return scan_properties(fd, id, DRM_MODE_OBJECT_CONNECTOR, out->props, + connector_info, sizeof(connector_info) / sizeof(connector_info[0])); +} + +bool wlr_drm_get_crtc_props(int fd, uint32_t id, union wlr_drm_crtc_props *out) { + return scan_properties(fd, id, DRM_MODE_OBJECT_CRTC, out->props, + crtc_info, sizeof(crtc_info) / sizeof(crtc_info[0])); +} + +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/util.c b/backend/drm/util.c new file mode 100644 index 00000000..656c070a --- /dev/null +++ b/backend/drm/util.c @@ -0,0 +1,303 @@ +#include +#include +#include +#include +#include +#include "backend/drm/util.h" +#include + +int32_t calculate_refresh_rate(drmModeModeInfo *mode) { + int32_t refresh = (mode->clock * 1000000LL / mode->htotal + + mode->vtotal / 2) / mode->vtotal; + + if (mode->flags & DRM_MODE_FLAG_INTERLACE) { + refresh *= 2; + } + + if (mode->flags & DRM_MODE_FLAG_DBLSCAN) { + refresh /= 2; + } + + if (mode->vscan > 1) { + refresh /= mode->vscan; + } + + return refresh; +} + +// Constructed from http://edid.tv/manufacturer +static const char *get_manufacturer(uint16_t id) { +#define ID(a, b, c) ((a & 0x1f) << 10) | ((b & 0x1f) << 5) | (c & 0x1f) + switch (id) { + case ID('A', 'A', 'A'): return "Avolites Ltd"; + case ID('A', 'C', 'I'): return "Ancor Communications Inc"; + case ID('A', 'C', 'R'): return "Acer Technologies"; + case ID('A', 'P', 'P'): return "Apple Computer Inc"; + case ID('B', 'N', 'O'): return "Bang & Olufsen"; + case ID('C', 'M', 'N'): return "Chimei Innolux Corporation"; + case ID('C', 'M', 'O'): return "Chi Mei Optoelectronics corp."; + case ID('C', 'R', 'O'): return "Extraordinary Technologies PTY Limited"; + case ID('D', 'E', 'L'): return "Dell Inc."; + case ID('D', 'O', 'N'): return "DENON, Ltd."; + case ID('E', 'N', 'C'): return "Eizo Nanao Corporation"; + case ID('E', 'P', 'H'): return "Epiphan Systems Inc."; + case ID('F', 'U', 'S'): return "Fujitsu Siemens Computers GmbH"; + case ID('G', 'S', 'M'): return "Goldstar Company Ltd"; + case ID('H', 'I', 'Q'): return "Kaohsiung Opto Electronics Americas, Inc."; + case ID('H', 'S', 'D'): return "HannStar Display Corp"; + case ID('H', 'W', 'P'): return "Hewlett Packard"; + case ID('I', 'N', 'T'): return "Interphase Corporation"; + case ID('I', 'V', 'M'): return "Iiyama North America"; + case ID('L', 'E', 'N'): return "Lenovo Group Limited"; + case ID('M', 'A', 'X'): return "Rogen Tech Distribution Inc"; + case ID('M', 'E', 'G'): return "Abeam Tech Ltd"; + case ID('M', 'E', 'I'): return "Panasonic Industry Company"; + case ID('M', 'T', 'C'): return "Mars-Tech Corporation"; + case ID('M', 'T', 'X'): return "Matrox"; + case ID('N', 'E', 'C'): return "NEC Corporation"; + case ID('O', 'N', 'K'): return "ONKYO Corporation"; + case ID('O', 'R', 'N'): return "ORION ELECTRIC CO., LTD."; + case ID('O', 'T', 'M'): return "Optoma Corporation"; + case ID('O', 'V', 'R'): return "Oculus VR, Inc."; + case ID('P', 'H', 'L'): return "Philips Consumer Electronics Company"; + case ID('P', 'I', 'O'): return "Pioneer Electronic Corporation"; + case ID('P', 'N', 'R'): return "Planar Systems, Inc."; + case ID('Q', 'D', 'S'): return "Quanta Display Inc."; + case ID('S', 'A', 'M'): return "Samsung Electric Company"; + case ID('S', 'E', 'C'): return "Seiko Epson Corporation"; + case ID('S', 'H', 'P'): return "Sharp Corporation"; + case ID('S', 'I', 'I'): return "Silicon Image, Inc."; + case ID('S', 'N', 'Y'): return "Sony"; + case ID('T', 'O', 'P'): return "Orion Communications Co., Ltd."; + case ID('T', 'S', 'B'): return "Toshiba America Info Systems Inc"; + case ID('T', 'S', 'T'): return "Transtream Inc"; + case ID('U', 'N', 'K'): return "Unknown"; + case ID('V', 'I', 'Z'): return "VIZIO, Inc"; + case ID('V', 'S', 'C'): return "ViewSonic Corporation"; + case ID('Y', 'M', 'H'): return "Yamaha Corporation"; + default: return "Unknown"; + } +#undef ID +} + +/* See https://en.wikipedia.org/wiki/Extended_Display_Identification_Data for layout of EDID data. + * We don't parse the EDID properly. We just expect to receive valid data. + */ +void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *data) { + if (!data || len < 128) { + snprintf(output->make, sizeof(output->make), ""); + snprintf(output->model, sizeof(output->model), ""); + return; + } + + uint16_t id = (data[8] << 8) | data[9]; + snprintf(output->make, sizeof(output->make), "%s", get_manufacturer(id)); + + output->phys_width = ((data[68] & 0xf0) << 4) | data[66]; + output->phys_height = ((data[68] & 0x0f) << 8) | data[67]; + + for (size_t i = 72; i <= 108; i += 18) { + uint16_t flag = (data[i] << 8) | data[i + 1]; + if (flag == 0 && data[i + 3] == 0xFC) { + sprintf(output->model, "%.13s", &data[i + 5]); + + // Monitor names are terminated by newline if they're too short + char *nl = strchr(output->model, '\n'); + if (nl) { + *nl = '\0'; + } + + break; + } + } +} + +const char *conn_get_name(uint32_t type_id) { + switch (type_id) { + case DRM_MODE_CONNECTOR_Unknown: return "Unknown"; + case DRM_MODE_CONNECTOR_VGA: return "VGA"; + case DRM_MODE_CONNECTOR_DVII: return "DVI-I"; + case DRM_MODE_CONNECTOR_DVID: return "DVI-D"; + case DRM_MODE_CONNECTOR_DVIA: return "DVI-A"; + case DRM_MODE_CONNECTOR_Composite: return "Composite"; + case DRM_MODE_CONNECTOR_SVIDEO: return "SVIDEO"; + case DRM_MODE_CONNECTOR_LVDS: return "LVDS"; + case DRM_MODE_CONNECTOR_Component: return "Component"; + case DRM_MODE_CONNECTOR_9PinDIN: return "DIN"; + case DRM_MODE_CONNECTOR_DisplayPort: return "DP"; + case DRM_MODE_CONNECTOR_HDMIA: return "HDMI-A"; + case DRM_MODE_CONNECTOR_HDMIB: return "HDMI-B"; + case DRM_MODE_CONNECTOR_TV: return "TV"; + case DRM_MODE_CONNECTOR_eDP: return "eDP"; + case DRM_MODE_CONNECTOR_VIRTUAL: return "Virtual"; + case DRM_MODE_CONNECTOR_DSI: return "DSI"; + default: return "Unknown"; + } +} + +static void free_fb(struct gbm_bo *bo, void *data) { + uint32_t id = (uintptr_t)data; + + if (id) { + struct gbm_device *gbm = gbm_bo_get_device(bo); + drmModeRmFB(gbm_device_get_fd(gbm), id); + } +} + +uint32_t get_fb_for_bo(struct gbm_bo *bo) { + uint32_t id = (uintptr_t)gbm_bo_get_user_data(bo); + if (id) { + return id; + } + + struct gbm_device *gbm = gbm_bo_get_device(bo); + + int fd = gbm_device_get_fd(gbm); + uint32_t width = gbm_bo_get_width(bo); + uint32_t height = gbm_bo_get_height(bo); + uint32_t handles[4] = {gbm_bo_get_handle(bo).u32}; + uint32_t pitches[4] = {gbm_bo_get_stride(bo)}; + uint32_t offsets[4] = {gbm_bo_get_offset(bo, 0)}; + uint32_t format = gbm_bo_get_format(bo); + + if (drmModeAddFB2(fd, width, height, format, handles, pitches, offsets, &id, 0)) { + wlr_log_errno(L_ERROR, "Unable to add DRM framebuffer"); + } + + gbm_bo_set_user_data(bo, (void *)(uintptr_t)id, free_fb); + + return id; +} + +static inline bool is_taken(size_t n, const uint32_t arr[static n], uint32_t key) { + for (size_t i = 0; i < n; ++i) { + if (arr[i] == key) { + return true; + } + } + return false; +} + +/* + * Store all of the non-recursive state in a struct, so we aren't literally + * passing 12 arguments to a function. + */ +struct match_state { + const size_t num_objs; + const uint32_t *restrict objs; + const size_t num_res; + size_t score; + size_t replaced; + uint32_t *restrict res; + uint32_t *restrict best; + const uint32_t *restrict orig; + bool exit_early; +}; + +/* + * skips: The number of SKIP elements encountered so far. + * score: The number of resources we've matched so far. + * replaced: The number of changes from the original solution. + * i: The index of the current element. + * + * This tries to match a solution as close to st->orig as it can. + * + * Returns whether we've set a new best element with this solution. + */ +static bool match_obj_(struct match_state *st, size_t skips, size_t score, size_t replaced, size_t i) { + // Finished + if (i >= st->num_res) { + if (score > st->score || (score == st->score && replaced < st->replaced)) { + st->score = score; + st->replaced = replaced; + memcpy(st->best, st->res, sizeof st->best[0] * st->num_res); + + if (st->score == st->num_objs && st->replaced == 0) { + st->exit_early = true; + } + st->exit_early = (st->score == st->num_res - skips + || st->score == st->num_objs) + && st->replaced == 0; + + return true; + } else { + return false; + } + } + + if (st->orig[i] == SKIP) { + st->res[i] = SKIP; + return match_obj_(st, skips + 1, score, replaced, i + 1); + } + + /* + * Attempt to use the current solution first, to try and avoid + * recalculating everything + */ + + if (st->orig[i] != UNMATCHED && !is_taken(i, st->res, st->orig[i])) { + st->res[i] = st->orig[i]; + if (match_obj_(st, skips, score + 1, replaced, i + 1)) { + return true; + } + } + + if (st->orig[i] != UNMATCHED) { + ++replaced; + } + + bool is_best = false; + for (st->res[i] = 0; st->res[i] < st->num_objs; ++st->res[i]) { + // We tried this earlier + if (st->res[i] == st->orig[i]) { + continue; + } + + // Not compatable + if (!(st->objs[st->res[i]] & (1 << i))) { + continue; + } + + // Already taken + if (is_taken(i, st->res, st->res[i])) { + continue; + } + + if (match_obj_(st, skips, score + 1, replaced, i + 1)) { + is_best = true; + } + + if (st->exit_early) { + return true; + } + } + + if (is_best) { + return true; + } + + // Maybe this resource can't be matched + st->res[i] = UNMATCHED; + return match_obj_(st, skips, score, replaced, i + 1); +} + +size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], + size_t num_res, const uint32_t res[static restrict num_res], + uint32_t out[static restrict num_res]) { + uint32_t solution[num_res]; + + struct match_state st = { + .num_objs = num_objs, + .num_res = num_res, + .score = 0, + .replaced = SIZE_MAX, + .objs = objs, + .res = solution, + .best = out, + .orig = res, + .exit_early = false, + }; + + match_obj_(&st, 0, 0, 0, 0); + return st.score; +} diff --git a/backend/meson.build b/backend/meson.build index 9e3b6fed..630bc284 100644 --- a/backend/meson.build +++ b/backend/meson.build @@ -5,10 +5,10 @@ backend_files = files( 'session/session.c', 'drm/backend.c', 'drm/drm.c', - 'drm/drm-atomic.c', - 'drm/drm-legacy.c', - 'drm/drm-properties.c', - 'drm/drm-util.c', + 'drm/iface_atomic.c', + 'drm/iface_legacy.c', + 'drm/properties.c', + 'drm/util.c', 'libinput/backend.c', 'libinput/events.c', 'libinput/keyboard.c', diff --git a/include/backend/drm-properties.h b/include/backend/drm-properties.h deleted file mode 100644 index 7de386ea..00000000 --- a/include/backend/drm-properties.h +++ /dev/null @@ -1,67 +0,0 @@ -#ifndef BACKEND_DRM_PROPERTIES_H -#define BACKEND_DRM_PROPERTIES_H - -#include -#include - -/* - * These types contain the property ids for several DRM objects. - * See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#kms-properties - * for more details. - */ - -union wlr_drm_connector_props { - struct { - uint32_t edid; - uint32_t dpms; - - // atomic-modesetting only - - uint32_t crtc_id; - }; - uint32_t props[3]; -}; - -union wlr_drm_crtc_props { - struct { - // Neither of these are guranteed to exist - uint32_t rotation; - uint32_t scaling_mode; - - // atomic-modesetting only - - uint32_t active; - uint32_t mode_id; - }; - uint32_t props[4]; -}; - -union wlr_drm_plane_props { - struct { - uint32_t type; - uint32_t rotation; // Not guranteed to exist - - // atomic-modesetting only - - uint32_t src_x; - uint32_t src_y; - uint32_t src_w; - uint32_t src_h; - uint32_t crtc_x; - uint32_t crtc_y; - uint32_t crtc_w; - uint32_t crtc_h; - uint32_t fb_id; - uint32_t crtc_id; - }; - uint32_t props[12]; -}; - -bool wlr_drm_get_connector_props(int fd, uint32_t id, union wlr_drm_connector_props *out); -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/include/backend/drm-util.h b/include/backend/drm-util.h deleted file mode 100644 index 6818b4db..00000000 --- a/include/backend/drm-util.h +++ /dev/null @@ -1,39 +0,0 @@ -#ifndef BACKEND_DRM_UTIL_H -#define BACKEND_DRM_UTIL_H - -#include -#include -#include -#include - -// Calculates a more accurate refresh rate (mHz) than what mode itself provides -int32_t calculate_refresh_rate(drmModeModeInfo *mode); -// Populates the make/model/phys_{width,height} of output from the edid data -void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *data); -// Returns the string representation of a DRM output type -const char *conn_get_name(uint32_t type_id); -// Returns the DRM framebuffer id for a gbm_bo -uint32_t get_fb_for_bo(struct gbm_bo *bo); - -// Part of match_obj -enum { - UNMATCHED = (uint32_t)-1, - SKIP = (uint32_t)-2, -}; - -/* - * Tries to match some DRM objects with some other DRM resource. - * e.g. Match CRTCs with Encoders, CRTCs with Planes. - * - * objs contains a bit array which resources it can be matched with. - * e.g. Bit 0 set means can be matched with res[0] - * - * res contains an index of which objs it is matched with or UNMATCHED. - * - * This solution is left in out. - * Returns the total number of matched solutions. - */ -size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], - size_t num_res, const uint32_t res[static restrict num_res], - uint32_t out[static restrict num_res]); -#endif diff --git a/include/backend/drm.h b/include/backend/drm.h deleted file mode 100644 index 6987b0bc..00000000 --- a/include/backend/drm.h +++ /dev/null @@ -1,186 +0,0 @@ -#ifndef BACKEND_DRM_H -#define BACKEND_DRM_H - -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include - -#include "drm-properties.h" - -struct wlr_drm_plane { - uint32_t type; - uint32_t id; - - uint32_t possible_crtcs; - - uint32_t width, height; - - struct gbm_surface *gbm; - EGLSurface egl; - - struct gbm_bo *front; - struct gbm_bo *back; - - // Only used by cursor - float matrix[16]; - struct wlr_renderer *wlr_rend; - struct wlr_texture *wlr_tex; - struct gbm_bo *cursor_bo; - - union wlr_drm_plane_props props; -}; - -struct wlr_drm_crtc { - uint32_t id; - uint32_t mode_id; // atomic modesetting only - drmModeAtomicReq *atomic; - - union { - struct { - struct wlr_drm_plane *overlay; - struct wlr_drm_plane *primary; - struct wlr_drm_plane *cursor; - }; - struct wlr_drm_plane *planes[3]; - }; - - union wlr_drm_crtc_props props; - - struct wl_list connectors; -}; - -struct wlr_drm_connector { - struct wlr_output *base; - uint32_t id; - struct wlr_drm_crtc *crtc; - - union wlr_drm_connector_props props; - - struct wl_list link; -}; - -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_drm_interface; - -struct wlr_drm_backend { - struct wlr_backend backend; - - const struct wlr_drm_interface *iface; - - int fd; - - size_t num_crtcs; - struct wlr_drm_crtc *crtcs; - size_t num_planes; - struct wlr_drm_plane *planes; - - union { - struct { - size_t num_overlay_planes; - size_t num_primary_planes; - size_t num_cursor_planes; - }; - size_t num_type_planes[3]; - }; - - union { - struct { - struct wlr_drm_plane *overlay_planes; - struct wlr_drm_plane *primary_planes; - struct wlr_drm_plane *cursor_planes; - }; - struct wlr_drm_plane *type_planes[3]; - }; - - struct wl_display *display; - struct wl_event_source *drm_event; - - struct wl_listener session_signal; - struct wl_listener drm_invalidated; - - list_t *outputs; - - struct wlr_drm_renderer renderer; - struct wlr_session *session; -}; - -enum wlr_drm_output_state { - WLR_DRM_OUTPUT_DISCONNECTED, - WLR_DRM_OUTPUT_NEEDS_MODESET, - WLR_DRM_OUTPUT_CLEANUP, - WLR_DRM_OUTPUT_CONNECTED, -}; - -struct wlr_drm_output_mode { - struct wlr_output_mode wlr_mode; - drmModeModeInfo mode; -}; - -struct wlr_drm_output { - struct wlr_output output; - - enum wlr_drm_output_state state; - uint32_t connector; - - struct wlr_drm_crtc *crtc; - uint32_t possible_crtc; - - union wlr_drm_connector_props props; - - uint32_t width; - uint32_t height; - - drmModeCrtc *old_crtc; - - struct wlr_drm_renderer *renderer; - - bool pageflip_pending; - struct wl_event_source *retry_pageflip; -}; - -// Used to provide atomic or legacy DRM functions -struct wlr_drm_interface { - // Enable or disable DPMS for output - void (*conn_enable)(struct wlr_drm_backend *backend, - struct wlr_drm_output *output, bool enable); - // Pageflip on crtc. If mode is non-NULL perform a full modeset using it. - bool (*crtc_pageflip)(struct wlr_drm_backend *backend, - struct wlr_drm_output *output, struct wlr_drm_crtc *crtc, - uint32_t fb_id, drmModeModeInfo *mode); - // Enable the cursor buffer on crtc. Set bo to NULL to disable - bool (*crtc_set_cursor)(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, struct gbm_bo *bo); - // Move the cursor on crtc - bool (*crtc_move_cursor)(struct wlr_drm_backend *backend, - struct wlr_drm_crtc *crtc, int x, int y); -}; - -bool wlr_drm_check_features(struct wlr_drm_backend *drm); -bool wlr_drm_resources_init(struct wlr_drm_backend *drm); -void wlr_drm_resources_free(struct wlr_drm_backend *drm); -void wlr_drm_restore_outputs(struct wlr_drm_backend *drm); -void wlr_drm_output_cleanup(struct wlr_drm_output *output); -void wlr_drm_scan_connectors(struct wlr_drm_backend *state); -int wlr_drm_event(int fd, uint32_t mask, void *data); - -void wlr_drm_output_start_renderer(struct wlr_drm_output *output); - -#endif diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h new file mode 100644 index 00000000..43838495 --- /dev/null +++ b/include/backend/drm/drm.h @@ -0,0 +1,186 @@ +#ifndef BACKEND_DRM_DRM_H +#define BACKEND_DRM_DRM_H + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include + +#include "properties.h" + +struct wlr_drm_plane { + uint32_t type; + uint32_t id; + + uint32_t possible_crtcs; + + uint32_t width, height; + + struct gbm_surface *gbm; + EGLSurface egl; + + struct gbm_bo *front; + struct gbm_bo *back; + + // Only used by cursor + float matrix[16]; + struct wlr_renderer *wlr_rend; + struct wlr_texture *wlr_tex; + struct gbm_bo *cursor_bo; + + union wlr_drm_plane_props props; +}; + +struct wlr_drm_crtc { + uint32_t id; + uint32_t mode_id; // atomic modesetting only + drmModeAtomicReq *atomic; + + union { + struct { + struct wlr_drm_plane *overlay; + struct wlr_drm_plane *primary; + struct wlr_drm_plane *cursor; + }; + struct wlr_drm_plane *planes[3]; + }; + + union wlr_drm_crtc_props props; + + struct wl_list connectors; +}; + +struct wlr_drm_connector { + struct wlr_output *base; + uint32_t id; + struct wlr_drm_crtc *crtc; + + union wlr_drm_connector_props props; + + struct wl_list link; +}; + +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_drm_interface; + +struct wlr_drm_backend { + struct wlr_backend backend; + + const struct wlr_drm_interface *iface; + + int fd; + + size_t num_crtcs; + struct wlr_drm_crtc *crtcs; + size_t num_planes; + struct wlr_drm_plane *planes; + + union { + struct { + size_t num_overlay_planes; + size_t num_primary_planes; + size_t num_cursor_planes; + }; + size_t num_type_planes[3]; + }; + + union { + struct { + struct wlr_drm_plane *overlay_planes; + struct wlr_drm_plane *primary_planes; + struct wlr_drm_plane *cursor_planes; + }; + struct wlr_drm_plane *type_planes[3]; + }; + + struct wl_display *display; + struct wl_event_source *drm_event; + + struct wl_listener session_signal; + struct wl_listener drm_invalidated; + + list_t *outputs; + + struct wlr_drm_renderer renderer; + struct wlr_session *session; +}; + +enum wlr_drm_output_state { + WLR_DRM_OUTPUT_DISCONNECTED, + WLR_DRM_OUTPUT_NEEDS_MODESET, + WLR_DRM_OUTPUT_CLEANUP, + WLR_DRM_OUTPUT_CONNECTED, +}; + +struct wlr_drm_output_mode { + struct wlr_output_mode wlr_mode; + drmModeModeInfo mode; +}; + +struct wlr_drm_output { + struct wlr_output output; + + enum wlr_drm_output_state state; + uint32_t connector; + + struct wlr_drm_crtc *crtc; + uint32_t possible_crtc; + + union wlr_drm_connector_props props; + + uint32_t width; + uint32_t height; + + drmModeCrtc *old_crtc; + + struct wlr_drm_renderer *renderer; + + bool pageflip_pending; + struct wl_event_source *retry_pageflip; +}; + +// Used to provide atomic or legacy DRM functions +struct wlr_drm_interface { + // Enable or disable DPMS for output + void (*conn_enable)(struct wlr_drm_backend *backend, + struct wlr_drm_output *output, bool enable); + // Pageflip on crtc. If mode is non-NULL perform a full modeset using it. + bool (*crtc_pageflip)(struct wlr_drm_backend *backend, + struct wlr_drm_output *output, struct wlr_drm_crtc *crtc, + uint32_t fb_id, drmModeModeInfo *mode); + // Enable the cursor buffer on crtc. Set bo to NULL to disable + bool (*crtc_set_cursor)(struct wlr_drm_backend *backend, + struct wlr_drm_crtc *crtc, struct gbm_bo *bo); + // Move the cursor on crtc + bool (*crtc_move_cursor)(struct wlr_drm_backend *backend, + struct wlr_drm_crtc *crtc, int x, int y); +}; + +bool wlr_drm_check_features(struct wlr_drm_backend *drm); +bool wlr_drm_resources_init(struct wlr_drm_backend *drm); +void wlr_drm_resources_free(struct wlr_drm_backend *drm); +void wlr_drm_restore_outputs(struct wlr_drm_backend *drm); +void wlr_drm_output_cleanup(struct wlr_drm_output *output); +void wlr_drm_scan_connectors(struct wlr_drm_backend *state); +int wlr_drm_event(int fd, uint32_t mask, void *data); + +void wlr_drm_output_start_renderer(struct wlr_drm_output *output); + +#endif diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h new file mode 100644 index 00000000..7de386ea --- /dev/null +++ b/include/backend/drm/properties.h @@ -0,0 +1,67 @@ +#ifndef BACKEND_DRM_PROPERTIES_H +#define BACKEND_DRM_PROPERTIES_H + +#include +#include + +/* + * These types contain the property ids for several DRM objects. + * See https://01.org/linuxgraphics/gfx-docs/drm/gpu/drm-kms.html#kms-properties + * for more details. + */ + +union wlr_drm_connector_props { + struct { + uint32_t edid; + uint32_t dpms; + + // atomic-modesetting only + + uint32_t crtc_id; + }; + uint32_t props[3]; +}; + +union wlr_drm_crtc_props { + struct { + // Neither of these are guranteed to exist + uint32_t rotation; + uint32_t scaling_mode; + + // atomic-modesetting only + + uint32_t active; + uint32_t mode_id; + }; + uint32_t props[4]; +}; + +union wlr_drm_plane_props { + struct { + uint32_t type; + uint32_t rotation; // Not guranteed to exist + + // atomic-modesetting only + + uint32_t src_x; + uint32_t src_y; + uint32_t src_w; + uint32_t src_h; + uint32_t crtc_x; + uint32_t crtc_y; + uint32_t crtc_w; + uint32_t crtc_h; + uint32_t fb_id; + uint32_t crtc_id; + }; + uint32_t props[12]; +}; + +bool wlr_drm_get_connector_props(int fd, uint32_t id, union wlr_drm_connector_props *out); +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/include/backend/drm/util.h b/include/backend/drm/util.h new file mode 100644 index 00000000..6818b4db --- /dev/null +++ b/include/backend/drm/util.h @@ -0,0 +1,39 @@ +#ifndef BACKEND_DRM_UTIL_H +#define BACKEND_DRM_UTIL_H + +#include +#include +#include +#include + +// Calculates a more accurate refresh rate (mHz) than what mode itself provides +int32_t calculate_refresh_rate(drmModeModeInfo *mode); +// Populates the make/model/phys_{width,height} of output from the edid data +void parse_edid(struct wlr_output *restrict output, size_t len, const uint8_t *data); +// Returns the string representation of a DRM output type +const char *conn_get_name(uint32_t type_id); +// Returns the DRM framebuffer id for a gbm_bo +uint32_t get_fb_for_bo(struct gbm_bo *bo); + +// Part of match_obj +enum { + UNMATCHED = (uint32_t)-1, + SKIP = (uint32_t)-2, +}; + +/* + * Tries to match some DRM objects with some other DRM resource. + * e.g. Match CRTCs with Encoders, CRTCs with Planes. + * + * objs contains a bit array which resources it can be matched with. + * e.g. Bit 0 set means can be matched with res[0] + * + * res contains an index of which objs it is matched with or UNMATCHED. + * + * This solution is left in out. + * Returns the total number of matched solutions. + */ +size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs], + size_t num_res, const uint32_t res[static restrict num_res], + uint32_t out[static restrict num_res]); +#endif -- cgit v1.2.3