Skip to content
This repository has been archived by the owner on Nov 1, 2021. It is now read-only.

Introduce wlr_drm_lease_v1 #1730

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
171 changes: 161 additions & 10 deletions backend/drm/drm.c
Expand Up @@ -270,6 +270,7 @@ bool init_drm_resources(struct wlr_drm_backend *drm) {
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
crtc->id = res->crtcs[i];
crtc->legacy_crtc = drmModeGetCrtc(drm->fd, crtc->id);
crtc->lessee_id = 0;
get_drm_crtc_props(drm->fd, crtc->id, &crtc->props);
}

Expand Down Expand Up @@ -768,6 +769,8 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn);

bool drm_connector_set_mode(struct wlr_drm_connector *conn,
struct wlr_output_mode *wlr_mode) {
assert(conn->state != WLR_DRM_CONN_LEASED
&& "Use of leased connector is a programming error");
struct wlr_drm_backend *drm =
get_drm_backend_from_backend(conn->output.backend);

Expand Down Expand Up @@ -830,6 +833,8 @@ bool drm_connector_set_mode(struct wlr_drm_connector *conn,
struct wlr_output_mode *wlr_drm_connector_add_mode(struct wlr_output *output,
const drmModeModeInfo *modeinfo) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
assert(conn->state != WLR_DRM_CONN_LEASED
&& "Use of leased connector is a programming error");

if (modeinfo->type != DRM_MODE_TYPE_USERDEF) {
return NULL;
Expand Down Expand Up @@ -867,6 +872,8 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
enum wl_output_transform transform,
int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
assert((conn->state != WLR_DRM_CONN_LEASED || texture == NULL)
&& "Use of leased connector is a programming error");
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This texture == NULL exception is necessary because when the output is destroyed, its cursors are destroyed as well.

struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
struct wlr_drm_crtc *crtc = conn->crtc;

Expand Down Expand Up @@ -973,6 +980,8 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
static bool drm_connector_move_cursor(struct wlr_output *output,
int x, int y) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
assert(conn->state != WLR_DRM_CONN_LEASED
&& "Use of leased connector is a programming error");
if (!conn->crtc) {
return false;
}
Expand Down Expand Up @@ -1015,6 +1024,9 @@ bool drm_connector_is_cursor_visible(struct wlr_drm_connector *conn) {

static void drm_connector_destroy(struct wlr_output *output) {
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
if (conn->state == WLR_DRM_CONN_LEASED) {
return;
}
drm_connector_cleanup(conn);
drmModeFreeCrtc(conn->old_crtc);
wl_list_remove(&conn->link);
Expand Down Expand Up @@ -1082,10 +1094,17 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
uint32_t new_match[drm->num_crtcs];

for (size_t i = 0; i < drm->num_crtcs; ++i) {
previous_match[i] = UNMATCHED;
if (drm->crtcs[i].lessee_id != 0) {
/* Do not consider leased CRTCs */
previous_match[i] = SKIP;
} else {
previous_match[i] = UNMATCHED;
}
}

wlr_log(WLR_DEBUG, "State before reallocation:");
wlr_log(WLR_DEBUG, "noutputs: %zd; ncrtc: %zd",
num_outputs, drm->num_crtcs);
size_t i = 0;
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &drm->outputs, link) {
Expand Down Expand Up @@ -1123,7 +1142,7 @@ static void realloc_crtcs(struct wlr_drm_backend *drm) {
connector_match[i] = -1;
}
for (size_t i = 0; i < drm->num_crtcs; ++i) {
if (new_match[i] != UNMATCHED) {
if (new_match[i] != UNMATCHED && new_match[i] != SKIP) {
ddevault marked this conversation as resolved.
Show resolved Hide resolved
connector_match[new_match[i]] = i;
}
}
Expand Down Expand Up @@ -1233,6 +1252,19 @@ static uint32_t get_possible_crtcs(int fd, drmModeRes *res,
return ret;
}

static void drm_conn_init_wlr_output(struct wlr_drm_backend *drm,
struct wlr_drm_connector *wlr_conn, drmModeConnector *drm_conn) {
wlr_log(WLR_DEBUG, "Initializing wlr_output for drm connector %s-%d",
conn_get_name(drm_conn->connector_type),
drm_conn->connector_type_id);
memset(&wlr_conn->output, 0, sizeof(struct wlr_output));
wlr_output_init(&wlr_conn->output,
&drm->backend, &output_impl, drm->display);
snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name),
"%s-%"PRIu32, conn_get_name(drm_conn->connector_type),
drm_conn->connector_type_id);
}

void scan_drm_connectors(struct wlr_drm_backend *drm) {
/*
* This GPU is not really a modesetting device.
Expand All @@ -1258,6 +1290,14 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
size_t new_outputs_len = 0;
struct wlr_drm_connector *new_outputs[res->count_connectors + 1];

drmModeLesseeListPtr lessees = drmModeListLessees(drm->fd);
if (lessees->count > 0) {
wlr_log(WLR_INFO, "With active leases:");
for (uint32_t i = 0; i < lessees->count; ++i) {
wlr_log(WLR_INFO, "%d", lessees->lessees[i]);
}
}

for (int i = 0; i < res->count_connectors; ++i) {
drmModeConnector *drm_conn = drmModeGetConnector(drm->fd,
res->connectors[i]);
Expand Down Expand Up @@ -1286,22 +1326,19 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
drmModeFreeConnector(drm_conn);
continue;
}
wlr_output_init(&wlr_conn->output, &drm->backend, &output_impl,
drm->display);

drm_conn_init_wlr_output(drm, wlr_conn, drm_conn);

wlr_conn->state = WLR_DRM_CONN_DISCONNECTED;
wlr_conn->id = drm_conn->connector_id;

snprintf(wlr_conn->output.name, sizeof(wlr_conn->output.name),
"%s-%"PRIu32, conn_get_name(drm_conn->connector_type),
drm_conn->connector_type_id);

if (curr_enc) {
wlr_conn->old_crtc = drmModeGetCrtc(drm->fd, curr_enc->crtc_id);
}

wl_list_insert(drm->outputs.prev, &wlr_conn->link);
wlr_log(WLR_INFO, "Found connector '%s'", wlr_conn->output.name);
wlr_log(WLR_INFO, "Found connector '%s' (%d)",
wlr_conn->output.name, drm_conn->connector_id);
} else {
seen[index] = true;
}
Expand Down Expand Up @@ -1335,6 +1372,33 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
}
}

if (wlr_conn->state == WLR_DRM_CONN_LEASED) {
/* Was the lease terminated? */
bool found = false;
for (uint32_t n = 0; n < lessees->count; ++n) {
if (lessees->lessees[n] == wlr_conn->lessee_id) {
found = true;
}
}
if (!found) {
/* Yes, it was */
wlr_log(WLR_DEBUG, "scan_drm_connectors: DRM lease %d terminated",
wlr_conn->lessee_id);
wlr_conn->state = WLR_DRM_CONN_DISCONNECTED;
wlr_conn->lessee_id = 0;
for (size_t i = 0; i < drm->num_crtcs; ++i) {
if (drm->crtcs[i].lessee_id == wlr_conn->lessee_id) {
drm->crtcs[i].lessee_id = 0;
}
}
if (wlr_conn->lease_terminated_cb != NULL) {
wlr_conn->lease_terminated_cb(
wlr_conn, wlr_conn->lease_terminated_data);
}
drm_conn_init_wlr_output(drm, wlr_conn, drm_conn);
}
}

if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED &&
drm_conn->connection == DRM_MODE_CONNECTED) {
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name);
Expand All @@ -1349,6 +1413,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {

get_drm_connector_props(drm->fd, wlr_conn->id, &wlr_conn->props);

uint64_t non_desktop;
if (get_drm_prop(drm->fd, wlr_conn->id,
wlr_conn->props.non_desktop, &non_desktop)) {
wlr_log(WLR_INFO, "Non-desktop connector");
wlr_conn->output.non_desktop = non_desktop;
}

size_t edid_len = 0;
uint8_t *edid = get_drm_prop_blob(drm->fd,
wlr_conn->id, wlr_conn->props.edid, &edid_len);
Expand Down Expand Up @@ -1565,7 +1636,7 @@ void restore_drm_outputs(struct wlr_drm_backend *drm) {

wl_list_for_each(conn, &drm->outputs, link) {
drmModeCrtc *crtc = conn->old_crtc;
if (!crtc) {
if (!crtc || conn->state == WLR_DRM_CONN_LEASED) {
continue;
}

Expand Down Expand Up @@ -1617,7 +1688,87 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) {
break;
case WLR_DRM_CONN_DISCONNECTED:
break;
case WLR_DRM_CONN_LEASED:
return; // don't change state
}

conn->state = WLR_DRM_CONN_DISCONNECTED;
}

int drm_create_lease(struct wlr_drm_backend *backend,
struct wlr_drm_connector **conns, int nconns, uint32_t *lessee_id,
void (*lease_terminated_cb)(struct wlr_drm_connector *, void *),
void *lease_terminated_data) {
int nobjects = 0;
for (int i = 0; i < nconns; ++i) {
struct wlr_drm_connector *conn = conns[i];
assert(conn->state != WLR_DRM_CONN_LEASED);
nobjects += 0
+ 1 /* connector */
+ 1 /* crtc */
+ 1 /* primary plane */
+ (conn->crtc->cursor != NULL ? 1 : 0) /* cursor plane */
+ conn->crtc->num_overlays; /* overlay planes */
}
if (nobjects <= 0) {
wlr_log(WLR_ERROR, "Attempted DRM lease with <= 0 objects");
return -1;
}
wlr_log(WLR_DEBUG, "Issuing DRM lease with the %d objects:", nobjects);
uint32_t objects[nobjects + 1];
for (int i = 0, j = 0; i < nconns; ++i) {
struct wlr_drm_connector *conn = conns[i];
objects[j++] = conn->id;
objects[j++] = conn->crtc->id;
objects[j++] = conn->crtc->primary->id;
wlr_log(WLR_DEBUG, "connector: %d crtc: %d primary plane: %d",
conn->id, conn->crtc->id, conn->crtc->primary->id);
if (conn->crtc->cursor) {
wlr_log(WLR_DEBUG, "cursor plane: %d", conn->crtc->cursor->id);
objects[j++] = conn->crtc->cursor->id;
}
if (conn->crtc->num_overlays > 0) {
wlr_log(WLR_DEBUG, "+%zd overlay planes:", conn->crtc->num_overlays);
}
for (size_t k = 0; k < conn->crtc->num_overlays; ++k) {
objects[j++] = conn->crtc->overlays[k];
wlr_log(WLR_DEBUG, "\toverlay plane: %d", conn->crtc->overlays[k]);
}
}
int lease_fd = drmModeCreateLease(backend->fd,
objects, nobjects, 0, lessee_id);
if (lease_fd < 0) {
return lease_fd;
}
wlr_log(WLR_DEBUG, "Issued DRM lease %d", *lessee_id);
for (int i = 0; i < nconns; ++i) {
struct wlr_drm_connector *conn = conns[i];
conn->lessee_id = *lessee_id;
conn->crtc->lessee_id = *lessee_id;
conn->state = WLR_DRM_CONN_LEASED;
conn->lease_terminated_cb = lease_terminated_cb;
conn->lease_terminated_data = lease_terminated_data;
wlr_output_destroy(&conn->output);
}
return lease_fd;
}

int drm_terminate_lease(struct wlr_drm_backend *backend, uint32_t lessee_id) {
wlr_log(WLR_DEBUG, "Terminating DRM lease %d", lessee_id);
int r = drmModeRevokeLease(backend->fd, lessee_id);
struct wlr_drm_connector *conn;
wl_list_for_each(conn, &backend->outputs, link) {
if (conn->state == WLR_DRM_CONN_LEASED
&& conn->lessee_id == lessee_id) {
conn->lessee_id = 0;
/* Will be re-initialized in scan_drm_connectors */
}
}
for (size_t i = 0; i < backend->num_crtcs; ++i) {
if (backend->crtcs[i].lessee_id == lessee_id) {
backend->crtcs[i].lessee_id = 0;
}
}
scan_drm_connectors(backend);
return r;
}
1 change: 1 addition & 0 deletions backend/drm/properties.c
Expand Up @@ -24,6 +24,7 @@ static const struct prop_info connector_info[] = {
{ "EDID", INDEX(edid) },
{ "PATH", INDEX(path) },
{ "link-status", INDEX(link_status) },
{ "non-desktop", INDEX(non_desktop) },
{ "vrr_capable", INDEX(vrr_capable) },
#undef INDEX
};
Expand Down
19 changes: 19 additions & 0 deletions include/backend/drm/drm.h
Expand Up @@ -60,6 +60,8 @@ struct wlr_drm_crtc {
// Legacy only
drmModeCrtc *legacy_crtc;

uint32_t lessee_id;

struct wlr_drm_plane *primary;
struct wlr_drm_plane *cursor;

Expand Down Expand Up @@ -107,6 +109,8 @@ enum wlr_drm_connector_state {
WLR_DRM_CONN_NEEDS_MODESET,
WLR_DRM_CONN_CLEANUP,
WLR_DRM_CONN_CONNECTED,
// Connector has been leased to another DRM master
WLR_DRM_CONN_LEASED,
};

struct wlr_drm_mode {
Expand All @@ -121,6 +125,9 @@ struct wlr_drm_connector {
struct wlr_output_mode *desired_mode;
bool desired_enabled;
uint32_t id;
uint32_t lessee_id;
void (*lease_terminated_cb)(struct wlr_drm_connector *, void *);
void *lease_terminated_data;

struct wlr_drm_crtc *crtc;
uint32_t possible_crtc;
Expand Down Expand Up @@ -158,4 +165,16 @@ size_t drm_crtc_get_gamma_lut_size(struct wlr_drm_backend *drm,

struct wlr_drm_fb *plane_get_next_fb(struct wlr_drm_plane *plane);

bool legacy_crtc_set_cursor(struct wlr_drm_backend *drm,
struct wlr_drm_crtc *crtc, struct gbm_bo *bo);
bool legacy_crtc_move_cursor(struct wlr_drm_backend *drm,
struct wlr_drm_crtc *crtc, int x, int y);

/** Returns the leased file descriptor */
int drm_create_lease(struct wlr_drm_backend *backend,
struct wlr_drm_connector **conns, int nconns, uint32_t *lessee_id,
void (*lease_terminated_cb)(struct wlr_drm_connector *, void *),
void *lease_terminated_data);
int drm_terminate_lease(struct wlr_drm_backend *backend, uint32_t lessee_id);

#endif
1 change: 1 addition & 0 deletions include/backend/drm/properties.h
Expand Up @@ -16,6 +16,7 @@ union wlr_drm_connector_props {
uint32_t dpms;
uint32_t link_status; // not guaranteed to exist
uint32_t path;
uint32_t non_desktop;
uint32_t vrr_capable; // not guaranteed to exist

// atomic-modesetting only
Expand Down