From e516ea4c798d4c02e77836d5e8196decb90a8774 Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Tue, 9 Apr 2019 23:36:35 +0300 Subject: [PATCH] backend/drm: check format when scanning out DMA-BUF --- backend/drm/drm.c | 45 +++++++++++++++++++++++++++-- backend/drm/properties.c | 39 +++++++++++++------------ include/backend/drm/drm.h | 2 ++ include/backend/drm/properties.h | 3 +- include/wlr/render/drm_format_set.h | 3 ++ render/drm_format_set.c | 20 +++++++++++++ 6 files changed, 90 insertions(+), 22 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 2e9ce589..a2a117d6 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -123,6 +123,8 @@ static bool init_planes(struct wlr_drm_backend *drm) { uint32_t rgb_format = DRM_FORMAT_INVALID; for (size_t j = 0; j < plane->count_formats; ++j) { uint32_t fmt = plane->formats[j]; + wlr_drm_format_set_add(&p->formats, fmt, DRM_FORMAT_MOD_INVALID); + if (fmt == DRM_FORMAT_ARGB8888) { // Prefer formats with alpha channel rgb_format = fmt; @@ -141,6 +143,38 @@ static bool init_planes(struct wlr_drm_backend *drm) { } p->drm_format = rgb_format; + if (p->props.in_formats) { + uint64_t blob_id; + if (!get_drm_prop(drm->fd, p->id, p->props.in_formats, &blob_id)) { + wlr_log(WLR_ERROR, "Failed to read IN_FORMATS property"); + drmModeFreePlane(plane); + goto error_planes; + } + + drmModePropertyBlobRes *blob = + drmModeGetPropertyBlob(drm->fd, blob_id); + if (!blob) { + wlr_log(WLR_ERROR, "Failed to read IN_FORMATS blob"); + drmModeFreePlane(plane); + goto error_planes; + } + + struct drm_format_modifier_blob *data = blob->data; + uint32_t *fmts = (uint32_t *)((char *)data + data->formats_offset); + struct drm_format_modifier *mods = (struct drm_format_modifier *) + ((char *)data + data->modifiers_offset); + for (uint32_t i = 0; i < data->count_modifiers; ++i) { + for (int j = 0; j < 64; ++j) { + if (mods[i].formats & ((uint64_t)1 << j)) { + wlr_drm_format_set_add(&p->formats, + fmts[j + mods[i].offset], mods[i].modifier); + } + } + } + + drmModeFreePropertyBlob(blob); + } + drmModeFreePlane(plane); } @@ -215,6 +249,11 @@ void finish_drm_resources(struct wlr_drm_backend *drm) { return; } + for (size_t i = 0; i < drm->num_planes; ++i) { + struct wlr_drm_plane *p = &drm->planes[i]; + wlr_drm_format_set_finish(&p->formats); + } + for (size_t i = 0; i < drm->num_crtcs; ++i) { struct wlr_drm_crtc *crtc = &drm->crtcs[i]; drmModeAtomicFree(crtc->atomic); @@ -833,11 +872,13 @@ static bool drm_connector_set_dmabuf(struct wlr_output *output, return false; } - // TODO: check plane input formats - if (attribs->width != output->width || attribs->height != output->height) { return false; } + if (!wlr_drm_format_set_has(&crtc->primary->formats, + attribs->format, attribs->modifier)) { + return false; + } struct gbm_bo *bo = import_gbm_bo(&drm->renderer, attribs); if (bo == NULL) { diff --git a/backend/drm/properties.c b/backend/drm/properties.c index 5541d1be..010b71d4 100644 --- a/backend/drm/properties.c +++ b/backend/drm/properties.c @@ -19,38 +19,39 @@ struct prop_info { 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) }, - { "PATH", INDEX(path) }, + { "CRTC_ID", INDEX(crtc_id) }, + { "DPMS", INDEX(dpms) }, + { "EDID", INDEX(edid) }, + { "PATH", INDEX(path) }, { "link-status", INDEX(link_status) }, #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) }, - { "GAMMA_LUT", INDEX(gamma_lut) }, + { "ACTIVE", INDEX(active) }, + { "GAMMA_LUT", INDEX(gamma_lut) }, { "GAMMA_LUT_SIZE", INDEX(gamma_lut_size) }, - { "MODE_ID", INDEX(mode_id) }, - { "rotation", INDEX(rotation) }, - { "scaling mode", INDEX(scaling_mode) }, + { "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_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) }, + { "CRTC_W", INDEX(crtc_w) }, + { "CRTC_X", INDEX(crtc_x) }, + { "CRTC_Y", INDEX(crtc_y) }, + { "FB_ID", INDEX(fb_id) }, + { "IN_FORMATS", INDEX(in_formats) }, + { "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 }; diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index 6481f085..ba08449a 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include "iface.h" @@ -27,6 +28,7 @@ struct wlr_drm_plane { struct wlr_drm_surface mgpu_surf; uint32_t drm_format; // ARGB8888 or XRGB8888 + struct wlr_drm_format_set formats; // Only used by cursor float matrix[9]; diff --git a/include/backend/drm/properties.h b/include/backend/drm/properties.h index b4d43bdd..28f0dbe4 100644 --- a/include/backend/drm/properties.h +++ b/include/backend/drm/properties.h @@ -44,6 +44,7 @@ union wlr_drm_plane_props { struct { uint32_t type; uint32_t rotation; // Not guaranteed to exist + uint32_t in_formats; // Not guaranteed to exist // atomic-modesetting only @@ -58,7 +59,7 @@ union wlr_drm_plane_props { uint32_t fb_id; uint32_t crtc_id; }; - uint32_t props[12]; + uint32_t props[13]; }; bool get_drm_connector_props(int fd, uint32_t id, diff --git a/include/wlr/render/drm_format_set.h b/include/wlr/render/drm_format_set.h index 588914ae..15d4eea3 100644 --- a/include/wlr/render/drm_format_set.h +++ b/include/wlr/render/drm_format_set.h @@ -21,6 +21,9 @@ void wlr_drm_format_set_finish(struct wlr_drm_format_set *set); const struct wlr_drm_format *wlr_drm_format_set_get( const struct wlr_drm_format_set *set, uint32_t format); +bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set, + uint32_t format, uint64_t modifier); + bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, uint64_t modifier); diff --git a/render/drm_format_set.c b/render/drm_format_set.c index df683b6d..b09a68a4 100644 --- a/render/drm_format_set.c +++ b/render/drm_format_set.c @@ -35,6 +35,26 @@ const struct wlr_drm_format *wlr_drm_format_set_get( return ptr ? *ptr : NULL; } +bool wlr_drm_format_set_has(const struct wlr_drm_format_set *set, + uint32_t format, uint64_t modifier) { + const struct wlr_drm_format *fmt = wlr_drm_format_set_get(set, format); + if (!fmt) { + return false; + } + + if (modifier == DRM_FORMAT_MOD_INVALID) { + return true; + } + + for (size_t i = 0; i < fmt->len; ++i) { + if (fmt->modifiers[i] == modifier) { + return true; + } + } + + return false; +} + bool wlr_drm_format_set_add(struct wlr_drm_format_set *set, uint32_t format, uint64_t modifier) { struct wlr_drm_format **ptr = format_set_get_ref(set, format);