drm backend: implement DRM lease issuance
This commit is contained in:
parent
05ed202183
commit
1b96ba8232
|
@ -269,6 +269,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);
|
||||
}
|
||||
|
||||
|
@ -578,6 +579,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
|
||||
|
@ -618,6 +621,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;
|
||||
|
@ -654,6 +659,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");
|
||||
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
||||
|
||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||
|
@ -791,6 +798,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;
|
||||
|
@ -827,6 +836,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;
|
||||
|
@ -878,6 +889,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;
|
||||
|
@ -919,6 +932,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);
|
||||
|
@ -996,10 +1012,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) {
|
||||
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) {
|
||||
|
@ -1037,7 +1060,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) {
|
||||
connector_match[new_match[i]] = i;
|
||||
}
|
||||
}
|
||||
|
@ -1149,6 +1172,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.
|
||||
|
@ -1174,6 +1206,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]);
|
||||
|
@ -1202,8 +1242,8 @@ 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(
|
||||
|
@ -1212,16 +1252,13 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
|||
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;
|
||||
}
|
||||
|
@ -1255,6 +1292,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);
|
||||
|
@ -1476,7 +1540,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;
|
||||
}
|
||||
|
||||
|
@ -1531,7 +1595,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->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;
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
@ -98,6 +100,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 {
|
||||
|
@ -112,6 +116,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;
|
||||
|
@ -149,4 +156,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
|
||||
|
|
Loading…
Reference in New Issue