Merge upstream

This commit is contained in:
Christian Kröner 2022-02-23 21:43:41 +01:00
commit c673b684a0
203 changed files with 6752 additions and 4861 deletions

View file

@ -133,12 +133,15 @@ static void handle_dev_change(struct wl_listener *listener, void *data) {
return;
}
// TODO: add and handle lease uevents
switch (change->type) {
case WLR_DEVICE_HOTPLUG:;
case WLR_DEVICE_HOTPLUG:
wlr_log(WLR_DEBUG, "Received hotplug event for %s", drm->name);
scan_drm_connectors(drm, &change->hotplug);
break;
case WLR_DEVICE_LEASE:
wlr_log(WLR_DEBUG, "Received lease event for %s", drm->name);
scan_drm_leases(drm);
break;
default:
wlr_log(WLR_DEBUG, "Received unknown change event for %s", drm->name);
}
@ -232,10 +235,6 @@ struct wlr_backend *wlr_drm_backend_create(struct wl_display *display,
}
if (drm->parent) {
// Ensure we use the same renderer as the parent backend
drm->backend.renderer = wlr_backend_get_renderer(&drm->parent->backend);
assert(drm->backend.renderer != NULL);
if (!init_drm_renderer(drm, &drm->mgpu_renderer)) {
wlr_log(WLR_ERROR, "Failed to initialize renderer");
goto error_resources;

View file

@ -118,9 +118,15 @@ static bool add_plane(struct wlr_drm_backend *drm,
p->id = drm_plane->plane_id;
p->props = *props;
for (size_t j = 0; j < drm_plane->count_formats; ++j) {
wlr_drm_format_set_add(&p->formats, drm_plane->formats[j],
DRM_FORMAT_MOD_INVALID);
for (size_t i = 0; i < drm_plane->count_formats; ++i) {
// Force a LINEAR layout for the cursor if the driver doesn't support
// modifiers
wlr_drm_format_set_add(&p->formats, drm_plane->formats[i],
DRM_FORMAT_MOD_LINEAR);
if (type != DRM_PLANE_TYPE_CURSOR) {
wlr_drm_format_set_add(&p->formats, drm_plane->formats[i],
DRM_FORMAT_MOD_INVALID);
}
}
if (p->props.in_formats && drm->addfb2_modifiers) {
@ -136,27 +142,12 @@ static bool add_plane(struct wlr_drm_backend *drm,
goto error;
}
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);
}
}
drmModeFormatModifierIterator iter = {0};
while (drmModeFormatModifierBlobIterNext(blob, &iter)) {
wlr_drm_format_set_add(&p->formats, iter.fmt, iter.mod);
}
drmModeFreePropertyBlob(blob);
} else if (type == DRM_PLANE_TYPE_CURSOR) {
// Force a LINEAR layout for the cursor if the driver doesn't support
// modifiers
for (size_t i = 0; i < p->formats.len; ++i) {
wlr_drm_format_set_add(&p->formats, p->formats.formats[i]->format,
DRM_FORMAT_MOD_LINEAR);
}
}
switch (type) {
@ -1300,8 +1291,7 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl,
drm->display);
memcpy(wlr_conn->output.name, wlr_conn->name,
sizeof(wlr_conn->output.name));
wlr_output_set_name(&wlr_conn->output, wlr_conn->name);
wlr_conn->output.phys_width = drm_conn->mmWidth;
wlr_conn->output.phys_height = drm_conn->mmHeight;
@ -1431,6 +1421,36 @@ void scan_drm_connectors(struct wlr_drm_backend *drm,
}
}
void scan_drm_leases(struct wlr_drm_backend *drm) {
drmModeLesseeListRes *list = drmModeListLessees(drm->fd);
if (list == NULL) {
wlr_log_errno(WLR_ERROR, "drmModeListLessees failed");
return;
}
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->outputs, link) {
if (conn->lease == NULL) {
continue;
}
bool found = false;
for (size_t i = 0; i < list->count; i++) {
if (list->lessees[i] == conn->lease->lessee_id) {
found = true;
break;
}
}
if (!found) {
wlr_log(WLR_DEBUG, "DRM lease %"PRIu32" has been terminated",
conn->lease->lessee_id);
drm_lease_destroy(conn->lease);
}
}
drmFree(list);
}
static int mhz_to_nsec(int mhz) {
return 1000000000000LL / mhz;
}
@ -1560,17 +1580,13 @@ int wlr_drm_backend_get_non_master_fd(struct wlr_backend *backend) {
return fd;
}
/* TODO: make the function return a `wlr_drm_lease` to provide a destroy event
* that can be fired when the kernel notifies us through uevent that the lease
* has been destroyed
*/
int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs,
uint32_t *lessee_id) {
struct wlr_drm_lease *wlr_drm_create_lease(struct wlr_output **outputs,
size_t n_outputs, int *lease_fd_ptr) {
assert(outputs);
if (n_outputs == 0) {
wlr_log(WLR_ERROR, "Can't lease 0 outputs");
return -1;
return NULL;
}
struct wlr_drm_backend *drm =
@ -1581,11 +1597,11 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs,
for (size_t i = 0; i < n_outputs; ++i) {
struct wlr_drm_connector *conn =
get_drm_connector_from_output(outputs[i]);
assert(conn->lessee_id == 0);
assert(conn->lease == NULL);
if (conn->backend != drm) {
wlr_log(WLR_ERROR, "Can't lease output from different backends");
return -1;
return NULL;
}
objects[n_objects++] = conn->id;
@ -1593,7 +1609,7 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs,
if (!conn->crtc) {
wlr_log(WLR_ERROR, "Connector has no CRTC");
return -1;
return NULL;
}
objects[n_objects++] = conn->crtc->id;
@ -1610,50 +1626,63 @@ int wlr_drm_create_lease(struct wlr_output **outputs, size_t n_outputs,
assert(n_objects != 0);
wlr_log(WLR_DEBUG, "Issuing DRM lease with the %d objects", n_objects);
int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0,
lessee_id);
if (lease_fd < 0) {
return lease_fd;
struct wlr_drm_lease *lease = calloc(1, sizeof(*lease));
if (lease == NULL) {
return NULL;
}
wlr_log(WLR_DEBUG, "Issued DRM lease %"PRIu32, *lessee_id);
lease->backend = drm;
wl_signal_init(&lease->events.destroy);
wlr_log(WLR_DEBUG, "Issuing DRM lease with %d objects", n_objects);
int lease_fd = drmModeCreateLease(drm->fd, objects, n_objects, 0,
&lease->lessee_id);
if (lease_fd < 0) {
free(lease);
return NULL;
}
*lease_fd_ptr = lease_fd;
wlr_log(WLR_DEBUG, "Issued DRM lease %"PRIu32, lease->lessee_id);
for (size_t i = 0; i < n_outputs; ++i) {
struct wlr_drm_connector *conn =
get_drm_connector_from_output(outputs[i]);
conn->lessee_id = *lessee_id;
conn->crtc->lessee_id = *lessee_id;
conn->lease = lease;
conn->crtc->lease = lease;
}
return lease_fd;
return lease;
}
bool wlr_drm_backend_terminate_lease(struct wlr_backend *backend,
uint32_t lessee_id) {
wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lessee_id);
void wlr_drm_lease_terminate(struct wlr_drm_lease *lease) {
struct wlr_drm_backend *drm = lease->backend;
assert(backend);
struct wlr_drm_backend *drm = get_drm_backend_from_backend(backend);
int r = drmModeRevokeLease(drm->fd, lessee_id);
if (r < 0) {
wlr_log_errno(WLR_DEBUG, "Failed to terminate lease");
wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lease->lessee_id);
int ret = drmModeRevokeLease(drm->fd, lease->lessee_id);
if (ret < 0) {
wlr_log_errno(WLR_ERROR, "Failed to terminate lease");
}
drm_lease_destroy(lease);
}
void drm_lease_destroy(struct wlr_drm_lease *lease) {
struct wlr_drm_backend *drm = lease->backend;
wlr_signal_emit_safe(&lease->events.destroy, NULL);
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->outputs, link) {
if (conn->lessee_id == lessee_id) {
conn->lessee_id = 0;
/* Will be re-initialized in scan_drm_connectors */
if (conn->lease == lease) {
conn->lease = NULL;
}
}
for (size_t i = 0; i < drm->num_crtcs; ++i) {
if (drm->crtcs[i].lessee_id == lessee_id) {
drm->crtcs[i].lessee_id = 0;
if (drm->crtcs[i].lease == lease) {
drm->crtcs[i].lease = NULL;
}
}
return r >= 0;
free(lease);
}

View file

@ -151,9 +151,13 @@ static bool legacy_crtc_commit(struct wlr_drm_connector *conn,
int ret = drmModeSetCursor(drm->fd, crtc->id, cursor_handle,
cursor_width, cursor_height);
close_bo_handle(drm->fd, cursor_handle);
int set_cursor_errno = errno;
if (drmCloseBufferHandle(drm->fd, cursor_handle) != 0) {
wlr_log_errno(WLR_ERROR, "drmCloseBufferHandle failed");
}
if (ret != 0) {
wlr_drm_conn_log_errno(conn, WLR_DEBUG, "drmModeSetCursor failed");
wlr_drm_conn_log(conn, WLR_DEBUG, "drmModeSetCursor failed: %s",
strerror(set_cursor_errno));
return false;
}

View file

@ -4,6 +4,7 @@ wlr_files += files(
'cvt.c',
'drm.c',
'legacy.c',
'monitor.c',
'properties.c',
'renderer.c',
'util.c',

94
backend/drm/monitor.c Normal file
View file

@ -0,0 +1,94 @@
#include <wlr/util/log.h>
#include <stdlib.h>
#include "backend/drm/monitor.h"
#include "backend/multi.h"
#include "backend/session/session.h"
static void drm_backend_monitor_destroy(struct wlr_drm_backend_monitor* monitor) {
wl_list_remove(&monitor->session_add_drm_card.link);
wl_list_remove(&monitor->session_destroy.link);
wl_list_remove(&monitor->primary_drm_destroy.link);
wl_list_remove(&monitor->multi_destroy.link);
free(monitor);
}
static void handle_add_drm_card(struct wl_listener *listener, void *data) {
struct wlr_session_add_event *event = data;
struct wlr_drm_backend_monitor *backend_monitor =
wl_container_of(listener, backend_monitor, session_add_drm_card);
struct wlr_device *dev =
session_open_if_kms(backend_monitor->session, event->path);
if (!dev) {
wlr_log(WLR_ERROR, "Unable to open %s as DRM device", event->path);
return;
}
wlr_log(WLR_DEBUG, "Creating DRM backend for %s after hotplug", event->path);
struct wlr_backend *child_drm = wlr_drm_backend_create(
backend_monitor->session->display, backend_monitor->session,
dev, backend_monitor->primary_drm);
if (!child_drm) {
wlr_log(WLR_ERROR, "Failed to create DRM backend after hotplug");
return;
}
if (!wlr_multi_backend_add(backend_monitor->multi, child_drm)) {
wlr_log(WLR_ERROR, "Failed to add new drm backend to multi backend");
wlr_backend_destroy(child_drm);
return;
}
if (!wlr_backend_start(child_drm)) {
wlr_log(WLR_ERROR, "Failed to start new child DRM backend");
wlr_backend_destroy(child_drm);
}
}
static void handle_session_destroy(struct wl_listener *listener, void *data) {
struct wlr_drm_backend_monitor *backend_monitor =
wl_container_of(listener, backend_monitor, session_destroy);
drm_backend_monitor_destroy(backend_monitor);
}
static void handle_primary_drm_destroy(struct wl_listener *listener, void *data) {
struct wlr_drm_backend_monitor *backend_monitor =
wl_container_of(listener, backend_monitor, primary_drm_destroy);
drm_backend_monitor_destroy(backend_monitor);
}
static void handle_multi_destroy(struct wl_listener *listener, void *data) {
struct wlr_drm_backend_monitor *backend_monitor =
wl_container_of(listener, backend_monitor, multi_destroy);
drm_backend_monitor_destroy(backend_monitor);
}
struct wlr_drm_backend_monitor *drm_backend_monitor_create(
struct wlr_backend *multi,
struct wlr_backend *primary_drm,
struct wlr_session *session) {
struct wlr_drm_backend_monitor *monitor =
calloc(1, sizeof(struct wlr_drm_backend_monitor));
if (!monitor) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
monitor->multi = multi;
monitor->primary_drm = primary_drm;
monitor->session = session;
monitor->session_add_drm_card.notify = handle_add_drm_card;
wl_signal_add(&session->events.add_drm_card, &monitor->session_add_drm_card);
monitor->session_destroy.notify = handle_session_destroy;
wl_signal_add(&session->events.destroy, &monitor->session_destroy);
monitor->primary_drm_destroy.notify = handle_primary_drm_destroy;
wl_signal_add(&primary_drm->events.destroy, &monitor->primary_drm_destroy);
monitor->multi_destroy.notify = handle_multi_destroy;
wl_signal_add(&multi->events.destroy, &monitor->multi_destroy);
return monitor;
}

View file

@ -149,7 +149,7 @@ struct wlr_drm_format *drm_plane_pick_render_format(
const struct wlr_drm_format_set *plane_formats = &plane->formats;
uint32_t fmt = DRM_FORMAT_ARGB8888;
if (!wlr_drm_format_set_has(&plane->formats, fmt, DRM_FORMAT_MOD_INVALID)) {
if (!wlr_drm_format_set_get(&plane->formats, fmt)) {
const struct wlr_pixel_format_info *format_info =
drm_get_pixel_format_info(fmt);
assert(format_info != NULL &&
@ -220,6 +220,13 @@ static uint32_t get_fb_for_bo(struct wlr_drm_backend *drm,
wlr_log_errno(WLR_DEBUG, "drmModeAddFB2WithModifiers failed");
}
} else {
if (dmabuf->modifier != DRM_FORMAT_MOD_INVALID &&
dmabuf->modifier != DRM_FORMAT_MOD_LINEAR) {
wlr_log(WLR_ERROR, "Cannot import DRM framebuffer with explicit "
"modifier 0x%"PRIX64, dmabuf->modifier);
return 0;
}
int ret = drmModeAddFB2(drm->fd, dmabuf->width, dmabuf->height,
dmabuf->format, handles, dmabuf->stride, dmabuf->offset, &id, 0);
if (ret != 0 && dmabuf->format == DRM_FORMAT_ARGB8888 &&
@ -264,30 +271,62 @@ static void close_all_bo_handles(struct wlr_drm_backend *drm,
continue;
}
close_bo_handle(drm->fd, handles[i]);
if (drmCloseBufferHandle(drm->fd, handles[i]) != 0) {
wlr_log_errno(WLR_ERROR, "drmCloseBufferHandle failed");
}
}
}
static void drm_poisoned_fb_handle_destroy(struct wlr_addon *addon) {
wlr_addon_finish(addon);
free(addon);
}
static const struct wlr_addon_interface poisoned_fb_addon_impl = {
.name = "wlr_drm_poisoned_fb",
.destroy = drm_poisoned_fb_handle_destroy,
};
static bool is_buffer_poisoned(struct wlr_drm_backend *drm,
struct wlr_buffer *buf) {
return wlr_addon_find(&buf->addons, drm, &poisoned_fb_addon_impl) != NULL;
}
/**
* Mark the buffer as "poisoned", ie. it cannot be imported into KMS. This
* allows us to avoid repeatedly trying to import it when it's not
* scanout-capable.
*/
static void poison_buffer(struct wlr_drm_backend *drm,
struct wlr_buffer *buf) {
struct wlr_addon *addon = calloc(1, sizeof(*addon));
if (addon == NULL) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return;
}
wlr_addon_init(addon, &buf->addons, drm, &poisoned_fb_addon_impl);
wlr_log(WLR_DEBUG, "Poisoning buffer");
}
static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm,
struct wlr_buffer *buf, const struct wlr_drm_format_set *formats) {
struct wlr_dmabuf_attributes attribs;
if (!wlr_buffer_get_dmabuf(buf, &attribs)) {
wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer");
return NULL;
}
if (is_buffer_poisoned(drm, buf)) {
wlr_log(WLR_DEBUG, "Buffer is poisoned");
return NULL;
}
struct wlr_drm_fb *fb = calloc(1, sizeof(*fb));
if (!fb) {
wlr_log_errno(WLR_ERROR, "Allocation failed");
return NULL;
}
struct wlr_dmabuf_attributes attribs;
if (!wlr_buffer_get_dmabuf(buf, &attribs)) {
wlr_log(WLR_DEBUG, "Failed to get DMA-BUF from buffer");
goto error_get_dmabuf;
}
if (attribs.flags != 0) {
wlr_log(WLR_DEBUG, "Buffer with DMA-BUF flags 0x%"PRIX32" cannot be "
"scanned out", attribs.flags);
goto error_get_dmabuf;
}
if (formats && !wlr_drm_format_set_has(formats, attribs.format,
attribs.modifier)) {
// The format isn't supported by the plane. Try stripping the alpha
@ -301,7 +340,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm,
wlr_log(WLR_DEBUG, "Buffer format 0x%"PRIX32" with modifier "
"0x%"PRIX64" cannot be scanned out",
attribs.format, attribs.modifier);
goto error_get_dmabuf;
goto error_fb;
}
}
@ -317,6 +356,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm,
fb->id = get_fb_for_bo(drm, &attribs, handles);
if (!fb->id) {
wlr_log(WLR_DEBUG, "Failed to import BO in KMS");
poison_buffer(drm, buf);
goto error_bo_handle;
}
@ -332,7 +372,7 @@ static struct wlr_drm_fb *drm_fb_create(struct wlr_drm_backend *drm,
error_bo_handle:
close_all_bo_handles(drm, handles);
error_get_dmabuf:
error_fb:
free(fb);
return NULL;
}

View file

@ -355,14 +355,3 @@ size_t match_obj(size_t num_objs, const uint32_t objs[static restrict num_objs],
match_obj_(&st, 0, 0, 0, 0);
return st.score;
}
void close_bo_handle(int drm_fd, uint32_t handle) {
if (handle == 0) {
return;
}
struct drm_gem_close args = { .handle = handle };
if (drmIoctl(drm_fd, DRM_IOCTL_GEM_CLOSE, &args) != 0) {
wlr_log_errno(WLR_ERROR, "drmIoctl(GEM_CLOSE) failed");
}
}