Compare commits
5 Commits
dkondor-up
...
0.8.0
| Author | SHA1 | Date |
|---|---|---|
|
|
df77592b6e | |
|
|
d84eb9e9f5 | |
|
|
1b96ba8232 | |
|
|
05ed202183 | |
|
|
481fbbca58 |
|
|
@ -269,6 +269,7 @@ bool init_drm_resources(struct wlr_drm_backend *drm) {
|
||||||
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
|
struct wlr_drm_crtc *crtc = &drm->crtcs[i];
|
||||||
crtc->id = res->crtcs[i];
|
crtc->id = res->crtcs[i];
|
||||||
crtc->legacy_crtc = drmModeGetCrtc(drm->fd, crtc->id);
|
crtc->legacy_crtc = drmModeGetCrtc(drm->fd, crtc->id);
|
||||||
|
crtc->lessee_id = 0;
|
||||||
get_drm_crtc_props(drm->fd, crtc->id, &crtc->props);
|
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,
|
bool drm_connector_set_mode(struct wlr_output *output,
|
||||||
struct wlr_output_mode *mode) {
|
struct wlr_output_mode *mode) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_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);
|
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
||||||
if (conn->crtc == NULL) {
|
if (conn->crtc == NULL) {
|
||||||
// Maybe we can steal a CRTC from a disabled output
|
// 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,
|
bool wlr_drm_connector_add_mode(struct wlr_output *output,
|
||||||
const drmModeModeInfo *modeinfo) {
|
const drmModeModeInfo *modeinfo) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_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");
|
||||||
|
|
||||||
if (modeinfo->type != DRM_MODE_TYPE_USERDEF) {
|
if (modeinfo->type != DRM_MODE_TYPE_USERDEF) {
|
||||||
return false;
|
return false;
|
||||||
|
|
@ -654,6 +659,8 @@ static bool drm_connector_set_cursor(struct wlr_output *output,
|
||||||
enum wl_output_transform transform,
|
enum wl_output_transform transform,
|
||||||
int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {
|
int32_t hotspot_x, int32_t hotspot_y, bool update_texture) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_output(output);
|
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_backend *drm = get_drm_backend_from_backend(output->backend);
|
||||||
|
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
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,
|
static bool drm_connector_move_cursor(struct wlr_output *output,
|
||||||
int x, int y) {
|
int x, int y) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_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);
|
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
||||||
if (!conn->crtc) {
|
if (!conn->crtc) {
|
||||||
return false;
|
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) {
|
static bool drm_connector_schedule_frame(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_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);
|
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
||||||
if (!drm->session->active) {
|
if (!drm->session->active) {
|
||||||
return false;
|
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,
|
static bool drm_connector_attach_buffer(struct wlr_output *output,
|
||||||
struct wlr_buffer *buffer) {
|
struct wlr_buffer *buffer) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_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);
|
struct wlr_drm_backend *drm = get_drm_backend_from_backend(output->backend);
|
||||||
if (!drm->session->active) {
|
if (!drm->session->active) {
|
||||||
return false;
|
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) {
|
static void drm_connector_destroy(struct wlr_output *output) {
|
||||||
struct wlr_drm_connector *conn = get_drm_connector_from_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);
|
drm_connector_cleanup(conn);
|
||||||
drmModeFreeCrtc(conn->old_crtc);
|
drmModeFreeCrtc(conn->old_crtc);
|
||||||
wl_event_source_remove(conn->retry_pageflip);
|
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];
|
uint32_t new_match[drm->num_crtcs];
|
||||||
|
|
||||||
for (size_t i = 0; i < drm->num_crtcs; ++i) {
|
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;
|
previous_match[i] = UNMATCHED;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
wlr_log(WLR_DEBUG, "State before reallocation:");
|
wlr_log(WLR_DEBUG, "State before reallocation:");
|
||||||
|
wlr_log(WLR_DEBUG, "noutputs: %zd; ncrtc: %zd",
|
||||||
|
num_outputs, drm->num_crtcs);
|
||||||
size_t i = 0;
|
size_t i = 0;
|
||||||
struct wlr_drm_connector *conn;
|
struct wlr_drm_connector *conn;
|
||||||
wl_list_for_each(conn, &drm->outputs, link) {
|
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;
|
connector_match[i] = -1;
|
||||||
}
|
}
|
||||||
for (size_t i = 0; i < drm->num_crtcs; ++i) {
|
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;
|
connector_match[new_match[i]] = i;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1149,6 +1172,15 @@ static uint32_t get_possible_crtcs(int fd, drmModeRes *res,
|
||||||
return ret;
|
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) {
|
void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
/*
|
/*
|
||||||
* This GPU is not really a modesetting device.
|
* 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;
|
size_t new_outputs_len = 0;
|
||||||
struct wlr_drm_connector *new_outputs[res->count_connectors + 1];
|
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) {
|
for (int i = 0; i < res->count_connectors; ++i) {
|
||||||
drmModeConnector *drm_conn = drmModeGetConnector(drm->fd,
|
drmModeConnector *drm_conn = drmModeGetConnector(drm->fd,
|
||||||
res->connectors[i]);
|
res->connectors[i]);
|
||||||
|
|
@ -1202,26 +1242,23 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
drmModeFreeConnector(drm_conn);
|
drmModeFreeConnector(drm_conn);
|
||||||
continue;
|
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);
|
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->retry_pageflip = wl_event_loop_add_timer(
|
||||||
wlr_conn);
|
ev, retry_pageflip, wlr_conn);
|
||||||
|
|
||||||
wlr_conn->state = WLR_DRM_CONN_DISCONNECTED;
|
wlr_conn->state = WLR_DRM_CONN_DISCONNECTED;
|
||||||
wlr_conn->id = drm_conn->connector_id;
|
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) {
|
if (curr_enc) {
|
||||||
wlr_conn->old_crtc = drmModeGetCrtc(drm->fd, curr_enc->crtc_id);
|
wlr_conn->old_crtc = drmModeGetCrtc(drm->fd, curr_enc->crtc_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_insert(drm->outputs.prev, &wlr_conn->link);
|
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 {
|
} else {
|
||||||
seen[index] = true;
|
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 &&
|
if (wlr_conn->state == WLR_DRM_CONN_DISCONNECTED &&
|
||||||
drm_conn->connection == DRM_MODE_CONNECTED) {
|
drm_conn->connection == DRM_MODE_CONNECTED) {
|
||||||
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name);
|
wlr_log(WLR_INFO, "'%s' connected", wlr_conn->output.name);
|
||||||
|
|
@ -1269,6 +1333,12 @@ void scan_drm_connectors(struct wlr_drm_backend *drm) {
|
||||||
|
|
||||||
get_drm_connector_props(drm->fd, wlr_conn->id, &wlr_conn->props);
|
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;
|
size_t edid_len = 0;
|
||||||
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
uint8_t *edid = get_drm_prop_blob(drm->fd,
|
||||||
wlr_conn->id, wlr_conn->props.edid, &edid_len);
|
wlr_conn->id, wlr_conn->props.edid, &edid_len);
|
||||||
|
|
@ -1470,7 +1540,7 @@ void restore_drm_outputs(struct wlr_drm_backend *drm) {
|
||||||
|
|
||||||
wl_list_for_each(conn, &drm->outputs, link) {
|
wl_list_for_each(conn, &drm->outputs, link) {
|
||||||
drmModeCrtc *crtc = conn->old_crtc;
|
drmModeCrtc *crtc = conn->old_crtc;
|
||||||
if (!crtc) {
|
if (!crtc || conn->state == WLR_DRM_CONN_LEASED) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -1525,7 +1595,87 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) {
|
||||||
break;
|
break;
|
||||||
case WLR_DRM_CONN_DISCONNECTED:
|
case WLR_DRM_CONN_DISCONNECTED:
|
||||||
break;
|
break;
|
||||||
|
case WLR_DRM_CONN_LEASED:
|
||||||
|
return; // don't change state
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->state = WLR_DRM_CONN_DISCONNECTED;
|
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) },
|
{ "EDID", INDEX(edid) },
|
||||||
{ "PATH", INDEX(path) },
|
{ "PATH", INDEX(path) },
|
||||||
{ "link-status", INDEX(link_status) },
|
{ "link-status", INDEX(link_status) },
|
||||||
|
{ "non-desktop", INDEX(non_desktop) },
|
||||||
#undef INDEX
|
#undef INDEX
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -47,6 +47,8 @@ struct wlr_drm_crtc {
|
||||||
// Legacy only
|
// Legacy only
|
||||||
drmModeCrtc *legacy_crtc;
|
drmModeCrtc *legacy_crtc;
|
||||||
|
|
||||||
|
uint32_t lessee_id;
|
||||||
|
|
||||||
struct wlr_drm_plane *primary;
|
struct wlr_drm_plane *primary;
|
||||||
struct wlr_drm_plane *cursor;
|
struct wlr_drm_plane *cursor;
|
||||||
|
|
||||||
|
|
@ -98,6 +100,8 @@ enum wlr_drm_connector_state {
|
||||||
WLR_DRM_CONN_NEEDS_MODESET,
|
WLR_DRM_CONN_NEEDS_MODESET,
|
||||||
WLR_DRM_CONN_CLEANUP,
|
WLR_DRM_CONN_CLEANUP,
|
||||||
WLR_DRM_CONN_CONNECTED,
|
WLR_DRM_CONN_CONNECTED,
|
||||||
|
// Connector has been leased to another DRM master
|
||||||
|
WLR_DRM_CONN_LEASED,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_drm_mode {
|
struct wlr_drm_mode {
|
||||||
|
|
@ -112,6 +116,9 @@ struct wlr_drm_connector {
|
||||||
struct wlr_output_mode *desired_mode;
|
struct wlr_output_mode *desired_mode;
|
||||||
bool desired_enabled;
|
bool desired_enabled;
|
||||||
uint32_t id;
|
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;
|
struct wlr_drm_crtc *crtc;
|
||||||
uint32_t possible_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,
|
bool drm_connector_set_mode(struct wlr_output *output,
|
||||||
struct wlr_output_mode *mode);
|
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
|
#endif
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@ union wlr_drm_connector_props {
|
||||||
uint32_t dpms;
|
uint32_t dpms;
|
||||||
uint32_t link_status; // not guaranteed to exist
|
uint32_t link_status; // not guaranteed to exist
|
||||||
uint32_t path;
|
uint32_t path;
|
||||||
|
uint32_t non_desktop;
|
||||||
|
|
||||||
// atomic-modesetting only
|
// atomic-modesetting only
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,145 @@
|
||||||
|
/*
|
||||||
|
* This an unstable interface of wlroots. No guarantees are made regarding the
|
||||||
|
* future consistency of this API.
|
||||||
|
*/
|
||||||
|
#ifndef WLR_USE_UNSTABLE
|
||||||
|
#error "Add -DWLR_USE_UNSTABLE to enable unstable wlroots features"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef WLR_TYPES_WLR_DRM_LEASE_V1_H
|
||||||
|
#define WLR_TYPES_WLR_DRM_LEASE_V1_H
|
||||||
|
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <wlr/backend.h>
|
||||||
|
|
||||||
|
struct wlr_drm_backend;
|
||||||
|
|
||||||
|
struct wlr_drm_lease_manager_v1 {
|
||||||
|
struct wl_list resources; // wl_resource_get_link
|
||||||
|
struct wl_global *global;
|
||||||
|
struct wlr_drm_backend *backend;
|
||||||
|
|
||||||
|
struct wl_list connectors; // wlr_drm_lease_connector_v1::link
|
||||||
|
struct wl_list leases; // wl_resource_get_link
|
||||||
|
struct wl_list lease_requests; // wl_resource_get_link
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/**
|
||||||
|
* Upon receiving this signal, call
|
||||||
|
* wlr_drm_lease_manager_v1_grant_lease_request to grant a lease of the
|
||||||
|
* requested DRM resources, or
|
||||||
|
* wlr_drm_lease_manager_v1_reject_lease_request to reject the request.
|
||||||
|
*/
|
||||||
|
struct wl_signal lease_requested; // wlr_drm_lease_request_v1
|
||||||
|
} events;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct wlr_drm_connector;
|
||||||
|
struct wlr_drm_lease_v1;
|
||||||
|
|
||||||
|
/** Represents a connector which is available for leasing, and may be leased */
|
||||||
|
struct wlr_drm_lease_connector_v1 {
|
||||||
|
struct wlr_output *output;
|
||||||
|
struct wlr_drm_connector *drm_connector;
|
||||||
|
struct wl_list resources; // wl_resource_get_link
|
||||||
|
|
||||||
|
/** NULL if no client is currently leasing this connector */
|
||||||
|
struct wlr_drm_lease_v1 *active_lease;
|
||||||
|
|
||||||
|
struct wl_list link; // wlr_drm_lease_manager_v1::connectors
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents a connector which has been added to a lease or lease request */
|
||||||
|
struct wlr_drm_connector_lease_v1 {
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager;
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector;
|
||||||
|
struct wl_list link; // wlr_drm_lease_request_v1::connectors
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents a pending or submitted lease request */
|
||||||
|
struct wlr_drm_lease_request_v1 {
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager;
|
||||||
|
struct wl_resource *resource; // wlr_drm_manager_v1::lease_requests
|
||||||
|
struct wl_list connectors; // wlr_drm_connector_lease_v1::link
|
||||||
|
bool invalid;
|
||||||
|
|
||||||
|
/** NULL until the lease is submitted */
|
||||||
|
struct wlr_drm_lease_v1 *lease;
|
||||||
|
};
|
||||||
|
|
||||||
|
/** Represents an active or previously active lease */
|
||||||
|
struct wlr_drm_lease_v1 {
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager;
|
||||||
|
struct wl_resource *resource; // wlr_drm_manager_v1::leases
|
||||||
|
struct wl_list connectors; // wlr_drm_connector_lease_v1::link
|
||||||
|
uint32_t lessee_id;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
/**
|
||||||
|
* Upon receiving this signal, it is safe to re-use the leased
|
||||||
|
* resources. After the signal is processed, the backend will re-signal
|
||||||
|
* new_output events for each leased output.
|
||||||
|
*
|
||||||
|
* The lifetime of the lease reference after the signal handler returns
|
||||||
|
* is not defined.
|
||||||
|
*/
|
||||||
|
struct wl_signal revoked; // wlr_drm_lease_v1
|
||||||
|
} events;
|
||||||
|
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates a DRM lease manager. The backend supplied must be a DRM backend, or a
|
||||||
|
* multi-backend with a single DRM backend within. If the supplied backend is
|
||||||
|
* not suitable, NULL is returned.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_lease_manager_v1 *wlr_drm_lease_manager_v1_create(
|
||||||
|
struct wl_display *display, struct wlr_backend *backend);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Offers a wlr_output for lease. The offered output must be owned by the DRM
|
||||||
|
* backend associated with this lease manager.
|
||||||
|
*/
|
||||||
|
void wlr_drm_lease_manager_v1_offer_output(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager, struct wlr_output *output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Withdraws a previously offered output for lease. It is a programming error to
|
||||||
|
* call this function when there are any active leases for this output.
|
||||||
|
*/
|
||||||
|
void wlr_drm_lease_manager_v1_widthraw_output(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager, struct wlr_output *output);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Grants a client's lease request. The lease manager will then provision the
|
||||||
|
* DRM lease and transfer the file descriptor to the client. After calling this,
|
||||||
|
* each wlr_output leased is destroyed, and will be re-issued through
|
||||||
|
* wlr_backend.events.new_outputs when the lease is revoked.
|
||||||
|
*
|
||||||
|
* This will return NULL without leasing any resources if the lease is invalid;
|
||||||
|
* this can happen for example if two clients request the same resources and an
|
||||||
|
* attempt to grant both leases is made.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_lease_v1 *wlr_drm_lease_manager_v1_grant_lease_request(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager,
|
||||||
|
struct wlr_drm_lease_request_v1 *request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Rejects a client's lease request.
|
||||||
|
*/
|
||||||
|
void wlr_drm_lease_manager_v1_reject_lease_request(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager,
|
||||||
|
struct wlr_drm_lease_request_v1 *request);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Revokes a client's lease request. You may resume use of any of the outputs
|
||||||
|
* leased after making this call.
|
||||||
|
*/
|
||||||
|
void wlr_drm_lease_manager_v1_revoke_lease(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager,
|
||||||
|
struct wlr_drm_lease_v1 *lease);
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
@ -112,6 +112,9 @@ struct wlr_output {
|
||||||
bool frame_pending;
|
bool frame_pending;
|
||||||
float transform_matrix[9];
|
float transform_matrix[9];
|
||||||
|
|
||||||
|
// true, for example, with VR headsets
|
||||||
|
bool non_desktop;
|
||||||
|
|
||||||
struct wlr_output_state pending;
|
struct wlr_output_state pending;
|
||||||
|
|
||||||
struct {
|
struct {
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
project(
|
project(
|
||||||
'wlroots',
|
'wlroots',
|
||||||
'c',
|
'c',
|
||||||
version: '0.7.0',
|
version: '0.8.0',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
meson_version: '>=0.48.0',
|
meson_version: '>=0.48.0',
|
||||||
default_options: [
|
default_options: [
|
||||||
|
|
@ -14,7 +14,7 @@ project(
|
||||||
# Format of so_version is CURRENT, REVISION, AGE.
|
# Format of so_version is CURRENT, REVISION, AGE.
|
||||||
# See: https://autotools.io/libtool/version.html
|
# See: https://autotools.io/libtool/version.html
|
||||||
# for a reference about clean library versioning.
|
# for a reference about clean library versioning.
|
||||||
so_version = ['3', '5', '1']
|
so_version = ['3', '6', '1']
|
||||||
|
|
||||||
add_project_arguments([
|
add_project_arguments([
|
||||||
'-DWLR_USE_UNSTABLE',
|
'-DWLR_USE_UNSTABLE',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,246 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<protocol name="drm_lease_unstable_v1">
|
||||||
|
<copyright>
|
||||||
|
Copyright © 2018 NXP
|
||||||
|
Copyright © 2019 Status Research & Development GmbH.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a
|
||||||
|
copy of this software and associated documentation files (the "Software"),
|
||||||
|
to deal in the Software without restriction, including without limitation
|
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense,
|
||||||
|
and/or sell copies of the Software, and to permit persons to whom the
|
||||||
|
Software is furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice (including the next
|
||||||
|
paragraph) shall be included in all copies or substantial portions of the
|
||||||
|
Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
|
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
|
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
|
||||||
|
DEALINGS IN THE SOFTWARE.
|
||||||
|
</copyright>
|
||||||
|
|
||||||
|
<interface name="zwp_drm_lease_manager_v1" version="1">
|
||||||
|
<description summary="lease manager">
|
||||||
|
This protocol is used by Wayland compositors which act as Direct
|
||||||
|
Renderering Manager (DRM) masters to lease DRM resources to Wayland
|
||||||
|
clients. Once leased, the compositor will not use the leased resources
|
||||||
|
until the lease is revoked or the client closes the file descriptor.
|
||||||
|
|
||||||
|
The lease manager is used to advertise connectors which are available for
|
||||||
|
leasing, and by the client to negotiate a lease request.
|
||||||
|
|
||||||
|
Warning! The protocol described in this file is experimental and
|
||||||
|
backward incompatible changes may be made. Backward compatible changes
|
||||||
|
may be added together with the corresponding interface version bump.
|
||||||
|
Backward incompatible changes are done by bumping the version number in
|
||||||
|
the protocol and interface names and resetting the interface version.
|
||||||
|
Once the protocol is to be declared stable, the 'z' prefix and the
|
||||||
|
version number in the protocol and interface names are removed and the
|
||||||
|
interface version number is reset.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="stopped_manager" value="0"
|
||||||
|
summary="request sent to a manager which has been stopped"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="create_lease_request">
|
||||||
|
<description summary="create a lease request object">
|
||||||
|
Creates a lease request object.
|
||||||
|
|
||||||
|
See the documentation for zwp_drm_lease_request_v1 for details.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_drm_lease_request_v1" />
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="stop">
|
||||||
|
<description summary="stop sending events">
|
||||||
|
Indicates the client no longer wishes to receive connector events. The
|
||||||
|
compositor may still send connector events until it sends the finish
|
||||||
|
event, however.
|
||||||
|
|
||||||
|
The client must not send any requests after this one.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<event name="connector">
|
||||||
|
<description summary="advertise connectors available for leases">
|
||||||
|
The compositor may choose to advertise 0 or more connectors which may be
|
||||||
|
leased to clients, and will use this event to do so. This object may be
|
||||||
|
passed into a lease request to lease that connector. See
|
||||||
|
zwp_drm_lease_request_v1.add_connector for details.
|
||||||
|
|
||||||
|
When this global is bound, the compositor will send all connectors
|
||||||
|
available for lease, but may send additional connectors at any time.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_drm_lease_connector_v1" />
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<description summary="the compositor has finished using the manager">
|
||||||
|
This event indicates that the compositor is done sending connector
|
||||||
|
events. The compositor will destroy this object immediately after
|
||||||
|
sending this event, and it will become invalid. The client should
|
||||||
|
release any resources associated with this manager after receiving this
|
||||||
|
event.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_drm_lease_connector_v1" version="1">
|
||||||
|
<description summary="a leasable DRM connector">
|
||||||
|
Represents a DRM connector which is available for lease. These objects are
|
||||||
|
created via zwp_drm_lease_manager_v1.connector, and should be passed into
|
||||||
|
lease requests via zwp_drm_lease_request_v1.add_connector.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="name">
|
||||||
|
<description summary="name">
|
||||||
|
The compositor sends this event once the connector is created to
|
||||||
|
indicate the name of this connector. This will not change for the
|
||||||
|
duration of the Wayland session, but is not guaranteed to be consistent
|
||||||
|
between sessions.
|
||||||
|
|
||||||
|
If the compositor also supports zxdg_output_manager_v1 and this
|
||||||
|
connector corresponds to a zxdg_output_v1, this name will match the
|
||||||
|
name of this zxdg_output_v1 object.
|
||||||
|
</description>
|
||||||
|
<arg name="name" type="string" summary="connector name" />
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="description">
|
||||||
|
<description summary="description">
|
||||||
|
The compositor sends this event once the connector is created to provide
|
||||||
|
a human-readable description for this connector, which may be presented
|
||||||
|
to the user.
|
||||||
|
</description>
|
||||||
|
<arg name="description" type="string" summary="connector description" />
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="connector_id">
|
||||||
|
<description summary="connector_id">
|
||||||
|
The compositor will send this event to indicate the DRM ID which
|
||||||
|
represents the underlying connector which is being offered. Note that
|
||||||
|
the final lease may include additional object IDs, such as CRTCs and
|
||||||
|
planes.
|
||||||
|
</description>
|
||||||
|
<arg name="connector_id" type="int" summary="DRM Connector ID" />
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="edid">
|
||||||
|
<description summary="edid">
|
||||||
|
The compositor may send this event once the connector is created to
|
||||||
|
provide a file descriptor which may be memory-mapped to read the
|
||||||
|
connector's EDID, to assist in selecting the correct connectors
|
||||||
|
for lease. The fd must be mapped with MAP_PRIVATE by the recipient.
|
||||||
|
|
||||||
|
Note that not all displays have an EDID, and this event will not be
|
||||||
|
sent in such cases.
|
||||||
|
</description>
|
||||||
|
<arg name="edid" type="fd" summary="EDID file descriptor" />
|
||||||
|
<arg name="size" type="uint" summary="EDID size, in bytes"/>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="withdrawn">
|
||||||
|
<description summary="lease offer withdrawn">
|
||||||
|
Sent to indicate that the compositor will no longer honor requests for
|
||||||
|
DRM leases which include this connector. The client may still issue a
|
||||||
|
lease request including this connector, but the compositor will send
|
||||||
|
zwp_drm_lease_v1.finished without issuing a lease fd.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroy connector">
|
||||||
|
The client may send this request to indicate that it will not issue a
|
||||||
|
lease request for this connector. Clients are encouraged to send this
|
||||||
|
after receiving the "withdrawn" request so that the server can release
|
||||||
|
the resources associated with this connector offer.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_drm_lease_request_v1" version="1">
|
||||||
|
<description summary="DRM lease request">
|
||||||
|
A client that wishes to lease DRM resources will attach the list of
|
||||||
|
connectors advertised with zwp_drm_lease_manager_v1.connector that they
|
||||||
|
wish to lease, then use zwp_drm_lease_request_v1.submit to submit the
|
||||||
|
request.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<enum name="error">
|
||||||
|
<entry name="submitted_lease" value="0"
|
||||||
|
summary="attempted to reuse a submitted lease"/>
|
||||||
|
</enum>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroys the lease request object">
|
||||||
|
Indicates that the client will no longer use this lease request.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="request_connector">
|
||||||
|
<description summary="request a connector for this lease">
|
||||||
|
Indicates that the client would like to lease the given connector.
|
||||||
|
This is only used as a suggestion, the compositor may choose to
|
||||||
|
include any resources in the lease it issues, or change the set of
|
||||||
|
leased resources at any time.
|
||||||
|
</description>
|
||||||
|
<arg name="connector" type="object"
|
||||||
|
interface="zwp_drm_lease_connector_v1" />
|
||||||
|
</request>
|
||||||
|
|
||||||
|
<request name="submit">
|
||||||
|
<description summary="submit the lease request">
|
||||||
|
Submits the lease request and creates a new zwp_drm_lease_v1 object.
|
||||||
|
After calling submit, issuing any other request than destroy is a
|
||||||
|
protocol error.
|
||||||
|
</description>
|
||||||
|
<arg name="id" type="new_id" interface="zwp_drm_lease_v1" />
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
|
||||||
|
<interface name="zwp_drm_lease_v1" version="1">
|
||||||
|
<description summary="a DRM lease">
|
||||||
|
A DRM lease object is used to transfer the DRM file descriptor to the
|
||||||
|
client and manage the lifetime of the lease.
|
||||||
|
</description>
|
||||||
|
|
||||||
|
<event name="lease_fd">
|
||||||
|
<description summary="shares the DRM file descriptor">
|
||||||
|
This event returns a file descriptor suitable for use with DRM-related
|
||||||
|
ioctls. The client should use drmModeGetLease to enumerate the DRM
|
||||||
|
objects which have been leased to them. If the compositor cannot or
|
||||||
|
will not grant a lease for the requested connectors, it will not send
|
||||||
|
this event, instead sending the finished event immediately.
|
||||||
|
|
||||||
|
It is a protocol error for the compositor to send this event more than
|
||||||
|
once for a given lease.
|
||||||
|
</description>
|
||||||
|
<arg name="leased_fd" type="fd" summary="leased DRM file descriptor" />
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<event name="finished">
|
||||||
|
<description summary="sent when the lease has been revoked">
|
||||||
|
When the compositor revokes the lease, it will issue this event to
|
||||||
|
notify clients of the change. If the client requires a new lease, they
|
||||||
|
should destroy this object and submit a new lease request. The
|
||||||
|
compositor will send no further events for this object after sending
|
||||||
|
the finish event.
|
||||||
|
</description>
|
||||||
|
</event>
|
||||||
|
|
||||||
|
<request name="destroy" type="destructor">
|
||||||
|
<description summary="destroys the lease object">
|
||||||
|
The client should send this to indicate that it no longer wishes to use
|
||||||
|
this lease. The compositor should use drmModeRevokeLease on the
|
||||||
|
appropriate file descriptor, if necessary, then release this object.
|
||||||
|
</description>
|
||||||
|
</request>
|
||||||
|
</interface>
|
||||||
|
</protocol>
|
||||||
|
|
@ -25,6 +25,7 @@ protocols = [
|
||||||
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
|
[wl_protocol_dir, 'unstable/xdg-decoration/xdg-decoration-unstable-v1.xml'],
|
||||||
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
[wl_protocol_dir, 'unstable/xdg-output/xdg-output-unstable-v1.xml'],
|
||||||
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
|
[wl_protocol_dir, 'unstable/xdg-shell/xdg-shell-unstable-v6.xml'],
|
||||||
|
'drm-lease-unstable-v1.xml',
|
||||||
'gtk-primary-selection.xml',
|
'gtk-primary-selection.xml',
|
||||||
'idle.xml',
|
'idle.xml',
|
||||||
'input-method-unstable-v2.xml',
|
'input-method-unstable-v2.xml',
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ lib_wlr_types = static_library(
|
||||||
'wlr_compositor.c',
|
'wlr_compositor.c',
|
||||||
'wlr_cursor.c',
|
'wlr_cursor.c',
|
||||||
'wlr_data_control_v1.c',
|
'wlr_data_control_v1.c',
|
||||||
|
'wlr_drm_lease_v1.c',
|
||||||
'wlr_export_dmabuf_v1.c',
|
'wlr_export_dmabuf_v1.c',
|
||||||
'wlr_foreign_toplevel_management_v1.c',
|
'wlr_foreign_toplevel_management_v1.c',
|
||||||
'wlr_fullscreen_shell_v1.c',
|
'wlr_fullscreen_shell_v1.c',
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,582 @@
|
||||||
|
#include <assert.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <sys/mman.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wlr/backend/drm.h>
|
||||||
|
#include <wlr/backend/multi.h>
|
||||||
|
#include <wlr/types/wlr_surface.h>
|
||||||
|
#include <wlr/types/wlr_drm_lease_v1.h>
|
||||||
|
#include <wlr/util/log.h>
|
||||||
|
#include <wayland-util.h>
|
||||||
|
#include <wayland-server.h>
|
||||||
|
#include <xf86drmMode.h>
|
||||||
|
#include "backend/drm/drm.h"
|
||||||
|
#include "drm-lease-unstable-v1-protocol.h"
|
||||||
|
#include "util/shm.h"
|
||||||
|
#include "util/signal.h"
|
||||||
|
|
||||||
|
static struct zwp_drm_lease_manager_v1_interface lease_manager_impl;
|
||||||
|
static struct zwp_drm_lease_request_v1_interface lease_request_impl;
|
||||||
|
static struct zwp_drm_lease_connector_v1_interface lease_connector_impl;
|
||||||
|
static struct zwp_drm_lease_v1_interface lease_impl;
|
||||||
|
|
||||||
|
static void drm_lease_connector_v1_send_to_client(
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector,
|
||||||
|
struct wl_client *wl_client, struct wl_resource *manager);
|
||||||
|
|
||||||
|
static struct wlr_drm_lease_manager_v1 *wlr_drm_lease_manager_v1_from_resource(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwp_drm_lease_manager_v1_interface, &lease_manager_impl));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_drm_lease_request_v1 *wlr_drm_lease_request_v1_from_resource(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwp_drm_lease_request_v1_interface, &lease_request_impl));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_drm_lease_connector_v1 *
|
||||||
|
wlr_drm_lease_connector_v1_from_resource(struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwp_drm_lease_connector_v1_interface, &lease_connector_impl));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct wlr_drm_lease_v1 *wlr_drm_lease_v1_from_resource(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
assert(wl_resource_instance_of(resource,
|
||||||
|
&zwp_drm_lease_v1_interface, &lease_impl));
|
||||||
|
return wl_resource_get_user_data(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool drm_lease_request_v1_validate(
|
||||||
|
struct wlr_drm_lease_request_v1 *req) {
|
||||||
|
if (req->invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
/* Don't lease connectors which are already leased */
|
||||||
|
struct wlr_drm_connector_lease_v1 *connector;
|
||||||
|
wl_list_for_each(connector, &req->connectors, link) {
|
||||||
|
if (connector->connector->active_lease) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lease_terminated_by_drm(
|
||||||
|
struct wlr_drm_connector *conn, void *data) {
|
||||||
|
wlr_log(WLR_DEBUG, "Lease terminated by DRM");
|
||||||
|
struct wlr_drm_lease_v1 *lease = data;
|
||||||
|
lease->lessee_id = 0;
|
||||||
|
wlr_drm_lease_manager_v1_revoke_lease(lease->manager, lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_lease_v1 *wlr_drm_lease_manager_v1_grant_lease_request(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager,
|
||||||
|
struct wlr_drm_lease_request_v1 *request) {
|
||||||
|
assert(manager && request);
|
||||||
|
assert(request->lease);
|
||||||
|
|
||||||
|
struct wlr_drm_lease_v1 *lease = request->lease;
|
||||||
|
if (!drm_lease_request_v1_validate(request)) {
|
||||||
|
zwp_drm_lease_v1_send_finished(lease->resource);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int nconns = 0;
|
||||||
|
|
||||||
|
/** Adopt the connector leases from the lease request */
|
||||||
|
struct wlr_drm_connector_lease_v1 *conn, *temp;
|
||||||
|
wl_list_for_each_safe(conn, temp, &request->connectors, link) {
|
||||||
|
wl_list_remove(&conn->link);
|
||||||
|
wl_list_init(&conn->link);
|
||||||
|
wl_list_insert(&lease->connectors, &conn->link);
|
||||||
|
++nconns;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_connector *conns[nconns + 1];
|
||||||
|
int i = 0;
|
||||||
|
wl_list_for_each(conn, &lease->connectors, link) {
|
||||||
|
conns[i] = conn->connector->drm_connector;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
|
||||||
|
int fd = drm_create_lease(manager->backend,
|
||||||
|
conns, nconns, &lease->lessee_id,
|
||||||
|
lease_terminated_by_drm, lease);
|
||||||
|
|
||||||
|
if (fd < 0) {
|
||||||
|
wlr_log_errno(WLR_ERROR, "drm_create_lease failed");
|
||||||
|
zwp_drm_lease_v1_send_finished(lease->resource);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_for_each(conn, &lease->connectors, link) {
|
||||||
|
struct wlr_drm_lease_connector_v1 *conn_lease =
|
||||||
|
conn->connector;
|
||||||
|
conn_lease->active_lease = lease;
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource, *temp;
|
||||||
|
wl_resource_for_each_safe(wl_resource, temp, &conn_lease->resources) {
|
||||||
|
zwp_drm_lease_connector_v1_send_withdrawn(wl_resource);
|
||||||
|
wl_resource_set_user_data(wl_resource, NULL);
|
||||||
|
wl_list_remove(wl_resource_get_link(wl_resource));
|
||||||
|
wl_list_init(wl_resource_get_link(wl_resource));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
zwp_drm_lease_v1_send_lease_fd(lease->resource, fd);
|
||||||
|
close(fd);
|
||||||
|
return lease;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_lease_manager_v1_reject_lease_request(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager,
|
||||||
|
struct wlr_drm_lease_request_v1 *request) {
|
||||||
|
assert(manager && request);
|
||||||
|
assert(request->lease);
|
||||||
|
zwp_drm_lease_v1_send_finished(request->lease->resource);
|
||||||
|
request->invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_lease_manager_v1_revoke_lease(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager,
|
||||||
|
struct wlr_drm_lease_v1 *lease) {
|
||||||
|
assert(manager && lease);
|
||||||
|
if (lease->resource != NULL) {
|
||||||
|
zwp_drm_lease_v1_send_finished(lease->resource);
|
||||||
|
}
|
||||||
|
if (lease->lessee_id != 0) {
|
||||||
|
if (drm_terminate_lease(manager->backend, lease->lessee_id) < 0) {
|
||||||
|
wlr_log_errno(WLR_DEBUG, "drm_terminate_lease");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct wlr_drm_connector_lease_v1 *conn;
|
||||||
|
wl_list_for_each(conn, &lease->connectors, link) {
|
||||||
|
struct wlr_drm_lease_connector_v1 *conn_lease =
|
||||||
|
conn->connector;
|
||||||
|
conn_lease->active_lease = NULL;
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource;
|
||||||
|
wl_resource_for_each(wl_resource, &manager->resources) {
|
||||||
|
struct wl_client *wl_client = wl_resource_get_client(wl_resource);
|
||||||
|
drm_lease_connector_v1_send_to_client(
|
||||||
|
conn_lease, wl_client, wl_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wlr_signal_emit_safe(&lease->events.revoked, lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_v1_destroy(struct wlr_drm_lease_v1 *lease) {
|
||||||
|
wlr_drm_lease_manager_v1_revoke_lease(lease->manager, lease);
|
||||||
|
free(lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_v1_handle_resource_destroy(struct wl_resource *resource) {
|
||||||
|
struct wlr_drm_lease_v1 *lease = wlr_drm_lease_v1_from_resource(resource);
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
wl_list_init(wl_resource_get_link(resource));
|
||||||
|
lease->resource = NULL;
|
||||||
|
drm_lease_v1_destroy(lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_v1_handle_destroy(
|
||||||
|
struct wl_client *client, struct wl_resource *resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_drm_lease_v1_interface lease_impl = {
|
||||||
|
.destroy = drm_lease_v1_handle_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void drm_lease_request_v1_destroy(struct wlr_drm_lease_request_v1 *req) {
|
||||||
|
if (!req) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
struct wlr_drm_connector_lease_v1 *conn, *temp;
|
||||||
|
wl_list_for_each_safe(conn, temp, &req->connectors, link) {
|
||||||
|
wl_list_remove(&conn->link);
|
||||||
|
wl_list_init(&conn->link);
|
||||||
|
free(conn);
|
||||||
|
}
|
||||||
|
free(req);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_request_v1_handle_resource_destroy(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
struct wlr_drm_lease_request_v1 *req =
|
||||||
|
wlr_drm_lease_request_v1_from_resource(resource);
|
||||||
|
drm_lease_request_v1_destroy(req);
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
wl_list_init(wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_request_v1_handle_destroy(
|
||||||
|
struct wl_client *client, struct wl_resource *resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_request_v1_handle_request_connector(
|
||||||
|
struct wl_client *client,
|
||||||
|
struct wl_resource *resource,
|
||||||
|
struct wl_resource *connector) {
|
||||||
|
struct wlr_drm_lease_request_v1 *request =
|
||||||
|
wlr_drm_lease_request_v1_from_resource(resource);
|
||||||
|
struct wlr_drm_lease_connector_v1 *conn =
|
||||||
|
wlr_drm_lease_connector_v1_from_resource(connector);
|
||||||
|
|
||||||
|
if (conn == NULL) {
|
||||||
|
/* This connector offer has been withdrawn */
|
||||||
|
request->invalid = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_connector_lease_v1 *lease =
|
||||||
|
calloc(1, sizeof(struct wlr_drm_connector_lease_v1));
|
||||||
|
if (!lease) {
|
||||||
|
wl_client_post_no_memory(client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lease->connector = conn;
|
||||||
|
wl_list_insert(&request->connectors, &lease->link);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_request_v1_handle_submit(
|
||||||
|
struct wl_client *client, struct wl_resource *resource, uint32_t id) {
|
||||||
|
struct wlr_drm_lease_request_v1 *lease_request =
|
||||||
|
wlr_drm_lease_request_v1_from_resource(resource);
|
||||||
|
|
||||||
|
struct wlr_drm_lease_v1 *lease = calloc(1, sizeof(struct wlr_drm_lease_v1));
|
||||||
|
if (!lease) {
|
||||||
|
wl_resource_post_no_memory(resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource = wl_resource_create(
|
||||||
|
client, &zwp_drm_lease_v1_interface, 1, id);
|
||||||
|
if (!wl_resource) {
|
||||||
|
free(lease);
|
||||||
|
wl_resource_post_no_memory(resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_signal_init(&lease->events.revoked);
|
||||||
|
wl_list_init(&lease->connectors);
|
||||||
|
lease->manager = lease_request->manager;
|
||||||
|
lease->resource = wl_resource;
|
||||||
|
lease_request->lease = lease;
|
||||||
|
wl_list_insert(&lease->manager->leases, wl_resource_get_link(wl_resource));
|
||||||
|
|
||||||
|
wl_resource_set_implementation(wl_resource, &lease_impl,
|
||||||
|
lease, drm_lease_v1_handle_resource_destroy);
|
||||||
|
|
||||||
|
if (!drm_lease_request_v1_validate(lease_request)) {
|
||||||
|
/* Pre-emptively reject invalid lease requests */
|
||||||
|
zwp_drm_lease_v1_send_finished(lease->resource);
|
||||||
|
} else {
|
||||||
|
wlr_signal_emit_safe(
|
||||||
|
&lease_request->manager->events.lease_requested,
|
||||||
|
lease_request);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_drm_lease_request_v1_interface lease_request_impl = {
|
||||||
|
.destroy = drm_lease_request_v1_handle_destroy,
|
||||||
|
.request_connector = drm_lease_request_v1_handle_request_connector,
|
||||||
|
.submit = drm_lease_request_v1_handle_submit,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void drm_lease_manager_v1_validate_destroy(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager, struct wl_client *client) {
|
||||||
|
// TODO: send protocol error if there are any bound resources
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_manager_v1_handle_resource_destroy(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
drm_lease_manager_v1_validate_destroy(
|
||||||
|
wlr_drm_lease_manager_v1_from_resource(resource),
|
||||||
|
wl_resource_get_client(resource));
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
wl_list_init(wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_lease_manager_v1_handle_stop(
|
||||||
|
struct wl_client *client, struct wl_resource *resource) {
|
||||||
|
zwp_drm_lease_manager_v1_send_finished(resource);
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
void drm_lease_manager_v1_handle_create_lease_request(
|
||||||
|
struct wl_client *client, struct wl_resource *resource, uint32_t id) {
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager =
|
||||||
|
wlr_drm_lease_manager_v1_from_resource(resource);
|
||||||
|
|
||||||
|
struct wlr_drm_lease_request_v1 *req =
|
||||||
|
calloc(1, sizeof(struct wlr_drm_lease_request_v1));
|
||||||
|
if (!req) {
|
||||||
|
wl_resource_post_no_memory(resource);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource = wl_resource_create(client,
|
||||||
|
&zwp_drm_lease_request_v1_interface, 1, id);
|
||||||
|
if (!wl_resource) {
|
||||||
|
wl_resource_post_no_memory(resource);
|
||||||
|
free(req);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
req->manager = manager;
|
||||||
|
req->resource = wl_resource;
|
||||||
|
wl_list_init(&req->connectors);
|
||||||
|
|
||||||
|
wl_resource_set_implementation(wl_resource, &lease_request_impl,
|
||||||
|
req, drm_lease_request_v1_handle_resource_destroy);
|
||||||
|
|
||||||
|
wl_list_insert(&manager->lease_requests, wl_resource_get_link(wl_resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_drm_lease_manager_v1_interface lease_manager_impl = {
|
||||||
|
.stop = drm_lease_manager_v1_handle_stop,
|
||||||
|
.create_lease_request = drm_lease_manager_v1_handle_create_lease_request,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void drm_connector_v1_handle_resource_destroy(
|
||||||
|
struct wl_resource *resource) {
|
||||||
|
wl_list_remove(wl_resource_get_link(resource));
|
||||||
|
wl_list_init(wl_resource_get_link(resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void drm_connector_v1_handle_destroy(
|
||||||
|
struct wl_client *client, struct wl_resource *resource) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct zwp_drm_lease_connector_v1_interface lease_connector_impl = {
|
||||||
|
.destroy = drm_connector_v1_handle_destroy,
|
||||||
|
};
|
||||||
|
|
||||||
|
static void drm_lease_connector_v1_send_to_client(
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector,
|
||||||
|
struct wl_client *wl_client, struct wl_resource *manager) {
|
||||||
|
if (connector->active_lease) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource = wl_resource_create(wl_client,
|
||||||
|
&zwp_drm_lease_connector_v1_interface, 1, 0);
|
||||||
|
wl_resource_set_implementation(wl_resource, &lease_connector_impl,
|
||||||
|
connector, drm_connector_v1_handle_resource_destroy);
|
||||||
|
zwp_drm_lease_manager_v1_send_connector(manager, wl_resource);
|
||||||
|
|
||||||
|
struct wlr_output *output = connector->output;
|
||||||
|
zwp_drm_lease_connector_v1_send_name(wl_resource, output->name);
|
||||||
|
|
||||||
|
char description[128];
|
||||||
|
snprintf(description, sizeof(description), "%s %s %s (%s)",
|
||||||
|
output->make, output->model, output->serial, output->name);
|
||||||
|
zwp_drm_lease_connector_v1_send_description(wl_resource, description);
|
||||||
|
|
||||||
|
zwp_drm_lease_connector_v1_send_connector_id(
|
||||||
|
wl_resource, connector->drm_connector->id);
|
||||||
|
|
||||||
|
struct wlr_drm_lease_manager_v1 *lease_manager =
|
||||||
|
wlr_drm_lease_manager_v1_from_resource(manager);
|
||||||
|
struct wlr_drm_connector *conn = connector->drm_connector;
|
||||||
|
size_t edid_len = 0;
|
||||||
|
uint8_t *edid = get_drm_prop_blob(lease_manager->backend->fd,
|
||||||
|
conn->id, conn->props.edid, &edid_len);
|
||||||
|
int edid_fd = allocate_shm_file(edid_len);
|
||||||
|
void *ptr = mmap(NULL, edid_len, PROT_READ | PROT_WRITE,
|
||||||
|
MAP_SHARED, edid_fd, 0);
|
||||||
|
memcpy(ptr, edid, edid_len);
|
||||||
|
munmap(ptr, edid_len);
|
||||||
|
|
||||||
|
zwp_drm_lease_connector_v1_send_edid(wl_resource, edid_fd, edid_len);
|
||||||
|
free(edid);
|
||||||
|
close(edid_fd);
|
||||||
|
|
||||||
|
wl_list_insert(&connector->resources, wl_resource_get_link(wl_resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void lease_manager_bind(struct wl_client *wl_client, void *data,
|
||||||
|
uint32_t version, uint32_t id) {
|
||||||
|
struct wlr_drm_lease_manager_v1 *lease_manager = data;
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource = wl_resource_create(wl_client,
|
||||||
|
&zwp_drm_lease_manager_v1_interface, version, id);
|
||||||
|
|
||||||
|
if (!wl_resource) {
|
||||||
|
wl_client_post_no_memory(wl_client);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_insert(&lease_manager->resources,
|
||||||
|
wl_resource_get_link(wl_resource));
|
||||||
|
|
||||||
|
wl_resource_set_implementation(wl_resource, &lease_manager_impl,
|
||||||
|
lease_manager, drm_lease_manager_v1_handle_resource_destroy);
|
||||||
|
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector;
|
||||||
|
wl_list_for_each(connector, &lease_manager->connectors, link) {
|
||||||
|
drm_lease_connector_v1_send_to_client(
|
||||||
|
connector, wl_client, wl_resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_lease_manager_v1_offer_output(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager, struct wlr_output *output) {
|
||||||
|
assert(manager && output);
|
||||||
|
assert(wlr_output_is_drm(output));
|
||||||
|
struct wlr_drm_connector *drm_connector =
|
||||||
|
(struct wlr_drm_connector *)output;
|
||||||
|
/*
|
||||||
|
* When the compositor grants a lease, we "destroy" all of the outputs on
|
||||||
|
* that lease. When the lease ends, the outputs re-appear. However, the
|
||||||
|
* underlying DRM connector remains the same. If the compositor offers
|
||||||
|
* outputs based on some criteria, then sees the output re-appear with the
|
||||||
|
* same critera, this code allows it to safely re-offer outputs which are
|
||||||
|
* backed by DRM connectors it has leased in the past.
|
||||||
|
*/
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector;
|
||||||
|
wl_list_for_each(connector, &manager->connectors, link) {
|
||||||
|
if (connector->drm_connector == drm_connector) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
connector = calloc(1, sizeof(struct wlr_drm_lease_connector_v1));
|
||||||
|
connector->drm_connector = drm_connector;
|
||||||
|
connector->output = &drm_connector->output;
|
||||||
|
wl_list_init(&connector->resources);
|
||||||
|
wl_list_insert(&manager->connectors, &connector->link);
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
wl_resource_for_each(resource, &manager->resources) {
|
||||||
|
drm_lease_connector_v1_send_to_client(
|
||||||
|
connector, wl_resource_get_client(resource), resource);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_lease_manager_v1_widthraw_output(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager, struct wlr_output *output) {
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector = NULL, *_connector;
|
||||||
|
wl_list_for_each(_connector, &manager->connectors, link) {
|
||||||
|
if (_connector->output == output) {
|
||||||
|
connector = _connector;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!connector) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
assert(connector->active_lease == NULL && "Cannot withdraw a leased output");
|
||||||
|
|
||||||
|
struct wl_resource *wl_resource, *temp;
|
||||||
|
wl_resource_for_each_safe(wl_resource, temp, &connector->resources) {
|
||||||
|
zwp_drm_lease_connector_v1_send_withdrawn(wl_resource);
|
||||||
|
wl_resource_set_user_data(wl_resource, NULL);
|
||||||
|
wl_list_remove(wl_resource_get_link(wl_resource));
|
||||||
|
wl_list_init(wl_resource_get_link(wl_resource));
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_resource_for_each(wl_resource, &manager->lease_requests) {
|
||||||
|
struct wlr_drm_lease_request_v1 *request =
|
||||||
|
wlr_drm_lease_request_v1_from_resource(wl_resource);
|
||||||
|
request->invalid = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_list_remove(&connector->link);
|
||||||
|
wl_list_init(&connector->link);
|
||||||
|
free(connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void multi_backend_cb(struct wlr_backend *backend, void *data) {
|
||||||
|
struct wlr_backend **ptr = data;
|
||||||
|
if (wlr_backend_is_drm(backend)) {
|
||||||
|
*ptr = backend;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_lease_manager_v1 *wlr_drm_lease_manager_v1_create(
|
||||||
|
struct wl_display *display, struct wlr_backend *backend) {
|
||||||
|
assert(display);
|
||||||
|
|
||||||
|
if (!wlr_backend_is_drm(backend) && wlr_backend_is_multi(backend)) {
|
||||||
|
wlr_multi_for_each_backend(backend, multi_backend_cb, &backend);
|
||||||
|
if (!wlr_backend_is_drm(backend)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_lease_manager_v1 *lease_manager =
|
||||||
|
calloc(1, sizeof(struct wlr_drm_lease_manager_v1));
|
||||||
|
|
||||||
|
if (!lease_manager) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
lease_manager->backend = get_drm_backend_from_backend(backend);
|
||||||
|
wl_list_init(&lease_manager->resources);
|
||||||
|
wl_list_init(&lease_manager->connectors);
|
||||||
|
wl_list_init(&lease_manager->lease_requests);
|
||||||
|
wl_list_init(&lease_manager->leases);
|
||||||
|
|
||||||
|
wl_signal_init(&lease_manager->events.lease_requested);
|
||||||
|
|
||||||
|
lease_manager->global = wl_global_create(display,
|
||||||
|
&zwp_drm_lease_manager_v1_interface, 1,
|
||||||
|
lease_manager, lease_manager_bind);
|
||||||
|
|
||||||
|
if (!lease_manager->global) {
|
||||||
|
free(lease_manager);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return lease_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
void wlr_drm_lease_manager_v1_destroy(
|
||||||
|
struct wlr_drm_lease_manager_v1 *manager) {
|
||||||
|
if (!manager) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wl_resource *resource;
|
||||||
|
struct wl_resource *tmp_resource;
|
||||||
|
wl_resource_for_each_safe(resource, tmp_resource, &manager->resources) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_resource_for_each_safe(resource, tmp_resource,
|
||||||
|
&manager->lease_requests) {
|
||||||
|
wl_resource_destroy(resource);
|
||||||
|
}
|
||||||
|
|
||||||
|
wl_resource_for_each_safe(resource, tmp_resource, &manager->leases) {
|
||||||
|
struct wlr_drm_lease_v1 *lease =
|
||||||
|
wlr_drm_lease_v1_from_resource(resource);
|
||||||
|
wlr_drm_lease_manager_v1_revoke_lease(manager, lease);
|
||||||
|
}
|
||||||
|
|
||||||
|
struct wlr_drm_lease_connector_v1 *connector, *tmp_connector;
|
||||||
|
wl_list_for_each_safe(connector, tmp_connector,
|
||||||
|
&manager->connectors, link) {
|
||||||
|
wl_list_remove(&connector->link);
|
||||||
|
wl_list_init(&connector->link);
|
||||||
|
free(connector);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(manager);
|
||||||
|
}
|
||||||
|
|
@ -90,7 +90,6 @@ static void manager_handle_create_inhibitor(struct wl_client *client,
|
||||||
inhibitor->surface_destroy.notify = idle_inhibitor_handle_surface_destroy;
|
inhibitor->surface_destroy.notify = idle_inhibitor_handle_surface_destroy;
|
||||||
wl_signal_add(&surface->events.destroy, &inhibitor->surface_destroy);
|
wl_signal_add(&surface->events.destroy, &inhibitor->surface_destroy);
|
||||||
|
|
||||||
|
|
||||||
wl_resource_set_implementation(wl_resource, &idle_inhibitor_impl,
|
wl_resource_set_implementation(wl_resource, &idle_inhibitor_impl,
|
||||||
inhibitor, idle_inhibitor_v1_handle_resource_destroy);
|
inhibitor, idle_inhibitor_v1_handle_resource_destroy);
|
||||||
|
|
||||||
|
|
@ -132,7 +131,8 @@ static void idle_inhibit_bind(struct wl_client *wl_client, void *data,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
wl_list_insert(&idle_inhibit->resources, wl_resource_get_link(wl_resource));
|
wl_list_insert(&idle_inhibit->resources,
|
||||||
|
wl_resource_get_link(wl_resource));
|
||||||
|
|
||||||
wl_resource_set_implementation(wl_resource, &idle_inhibit_impl,
|
wl_resource_set_implementation(wl_resource, &idle_inhibit_impl,
|
||||||
idle_inhibit, idle_inhibit_manager_v1_handle_resource_destroy);
|
idle_inhibit, idle_inhibit_manager_v1_handle_resource_destroy);
|
||||||
|
|
@ -155,7 +155,8 @@ void wlr_idle_inhibit_v1_destroy(struct wlr_idle_inhibit_manager_v1 *idle_inhibi
|
||||||
|
|
||||||
struct wl_resource *resource;
|
struct wl_resource *resource;
|
||||||
struct wl_resource *tmp_resource;
|
struct wl_resource *tmp_resource;
|
||||||
wl_resource_for_each_safe(resource, tmp_resource, &idle_inhibit->resources) {
|
wl_resource_for_each_safe(resource, tmp_resource,
|
||||||
|
&idle_inhibit->resources) {
|
||||||
wl_resource_destroy(resource);
|
wl_resource_destroy(resource);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue