Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce wlr_drm_lease_v1 #1730

Open
wants to merge 5 commits into
base: master
from
Open
Changes from all commits
Commits
File filter...
Filter file types
Jump to…
Jump to file or symbol
Failed to load files and symbols.

Always

Just for now

@@ -264,6 +264,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);
}

@@ -573,6 +574,8 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn);
bool drm_connector_set_mode(struct wlr_output *output,
struct wlr_output_mode *mode) {
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");
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
if (conn->crtc == NULL) {
// Maybe we can steal a CRTC from a disabled output
@@ -613,6 +616,8 @@ bool drm_connector_set_mode(struct wlr_output *output,
bool 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 false;
@@ -649,6 +654,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");

This comment has been minimized.

Copy link
@ddevault

ddevault Jun 27, 2019

Author Member

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;
@@ -786,6 +793,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");
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
if (!conn->crtc) {
return false;
@@ -822,6 +831,8 @@ static bool drm_connector_move_cursor(struct wlr_output *output,

static bool drm_connector_schedule_frame(struct wlr_output *output) {
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");
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
if (!drm->session->active) {
return false;
@@ -873,6 +884,8 @@ static uint32_t strip_alpha_channel(uint32_t format) {
static bool drm_connector_attach_buffer(struct wlr_output *output,
struct wlr_buffer *buffer) {
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");
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
if (!drm->session->active) {
return false;
@@ -914,6 +927,9 @@ static bool drm_connector_attach_buffer(struct wlr_output *output,

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_event_source_remove(conn->retry_pageflip);
@@ -991,10 +1007,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) {
@@ -1032,7 +1055,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) {
This conversation was marked as resolved by ddevault

This comment has been minimized.

Copy link
@ddevault

ddevault Jun 27, 2019

Author Member

Without this sway would crash when the lease is terminated, but I'm not 100% sure this is the right fix rather than a band-aid. Probably a consequence of the logic in the previous hunk, which may also be incorrect. Seems to work but w/e. Paging @ascent12 for comment.

This comment has been minimized.

Copy link
@ddevault

ddevault Jun 27, 2019

Author Member

Actually, this is definitely wrong.

This comment has been minimized.

Copy link
@ddevault

ddevault Jul 2, 2019

Author Member

Found the issue, it was elsewhere

connector_match[new_match[i]] = i;
}
}
@@ -1144,6 +1167,15 @@ 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_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.
@@ -1169,6 +1201,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]);
@@ -1197,26 +1237,23 @@ 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);

struct wl_event_loop *ev = wl_display_get_event_loop(drm->display);
wlr_conn->retry_pageflip = wl_event_loop_add_timer(ev, retry_pageflip,
wlr_conn);
wlr_conn->retry_pageflip = wl_event_loop_add_timer(
ev, retry_pageflip, wlr_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;
}
@@ -1250,6 +1287,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, "DRM lease %d terminated by kernel",
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);
@@ -1264,6 +1328,12 @@ 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_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);
@@ -1465,7 +1535,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;
}

@@ -1521,8 +1591,87 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) {
case WLR_DRM_CONN_DISCONNECTED:
break;
case WLR_DRM_CONN_DISAPPEARED:
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->state = WLR_DRM_CONN_DISCONNECTED;
conn->lessee_id = 0;
}
}
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;
}
@@ -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) },
#undef INDEX
};

@@ -47,6 +47,8 @@ struct wlr_drm_crtc {
// Legacy only
drmModeCrtc *legacy_crtc;

uint32_t lessee_id;

struct wlr_drm_plane *primary;
struct wlr_drm_plane *cursor;

@@ -100,6 +102,8 @@ enum wlr_drm_connector_state {
WLR_DRM_CONN_CONNECTED,
// Connector disappeared, waiting for being destroyed on next page-flip
WLR_DRM_CONN_DISAPPEARED,
// Connector has been leased to another DRM master
WLR_DRM_CONN_LEASED,
};

struct wlr_drm_mode {
@@ -114,6 +118,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;
@@ -151,4 +158,11 @@ bool set_drm_connector_gamma(struct wlr_output *output, size_t size,
bool drm_connector_set_mode(struct wlr_output *output,
struct wlr_output_mode *mode);

/** 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
@@ -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;

// atomic-modesetting only

@@ -24,6 +24,7 @@ struct roots_output_config {
int width, height;
float refresh_rate;
} mode;
bool lease;
struct wl_list modes;
};

ProTip! Use n and p to navigate between commits in a pull request.
You can’t perform that action at this time.