mirror of
https://github.com/hyprwm/wlroots-hyprland.git
synced 2024-11-26 06:35:58 +01:00
backend/drm: stash pending page-flip CRTC
wlr_drm_connector.crtc may be updated by the DRM backend while a page-flip is pending. In this case, the page-flip handler won't be able to find the right wlr_drm_connector from the CRTC ID. Save the CRTC when performing a page-flip to ensure we always find the right connector when we get the event.
This commit is contained in:
parent
576ff57db0
commit
adfb7cd35a
2 changed files with 18 additions and 14 deletions
|
@ -353,12 +353,13 @@ static bool drm_crtc_commit(struct wlr_drm_connector *conn, uint32_t flags) {
|
||||||
|
|
||||||
static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) {
|
static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) {
|
||||||
struct wlr_drm_crtc *crtc = conn->crtc;
|
struct wlr_drm_crtc *crtc = conn->crtc;
|
||||||
|
assert(crtc != NULL);
|
||||||
|
|
||||||
// wlr_drm_interface.crtc_commit will perform either a non-blocking
|
// wlr_drm_interface.crtc_commit will perform either a non-blocking
|
||||||
// page-flip, either a blocking modeset. When performing a blocking modeset
|
// page-flip, either a blocking modeset. When performing a blocking modeset
|
||||||
// we'll wait for all queued page-flips to complete, so we don't need this
|
// we'll wait for all queued page-flips to complete, so we don't need this
|
||||||
// safeguard.
|
// safeguard.
|
||||||
if (conn->pageflip_pending && !crtc->pending_modeset) {
|
if (conn->pending_page_flip_crtc && !crtc->pending_modeset) {
|
||||||
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to page-flip output: "
|
wlr_drm_conn_log(conn, WLR_ERROR, "Failed to page-flip output: "
|
||||||
"a page-flip is already pending");
|
"a page-flip is already pending");
|
||||||
return false;
|
return false;
|
||||||
|
@ -370,7 +371,7 @@ static bool drm_crtc_page_flip(struct wlr_drm_connector *conn) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->pageflip_pending = true;
|
conn->pending_page_flip_crtc = crtc->id;
|
||||||
|
|
||||||
// wlr_output's API guarantees that submitting a buffer will schedule a
|
// wlr_output's API guarantees that submitting a buffer will schedule a
|
||||||
// frame event. However the DRM backend will also schedule a frame event
|
// frame event. However the DRM backend will also schedule a frame event
|
||||||
|
@ -1017,7 +1018,7 @@ static void drm_connector_destroy_output(struct wlr_output *output) {
|
||||||
conn->desired_enabled = false;
|
conn->desired_enabled = false;
|
||||||
conn->desired_mode = NULL;
|
conn->desired_mode = NULL;
|
||||||
conn->possible_crtcs = 0;
|
conn->possible_crtcs = 0;
|
||||||
conn->pageflip_pending = false;
|
conn->pending_page_flip_crtc = 0;
|
||||||
|
|
||||||
struct wlr_drm_mode *mode, *mode_tmp;
|
struct wlr_drm_mode *mode, *mode_tmp;
|
||||||
wl_list_for_each_safe(mode, mode_tmp, &conn->output.modes, wlr_mode.link) {
|
wl_list_for_each_safe(mode, mode_tmp, &conn->output.modes, wlr_mode.link) {
|
||||||
|
@ -1443,22 +1444,24 @@ static void page_flip_handler(int fd, unsigned seq,
|
||||||
unsigned tv_sec, unsigned tv_usec, unsigned crtc_id, void *data) {
|
unsigned tv_sec, unsigned tv_usec, unsigned crtc_id, void *data) {
|
||||||
struct wlr_drm_backend *drm = data;
|
struct wlr_drm_backend *drm = data;
|
||||||
|
|
||||||
struct wlr_drm_connector *conn = NULL;
|
bool found = false;
|
||||||
struct wlr_drm_connector *search;
|
struct wlr_drm_connector *conn;
|
||||||
wl_list_for_each(search, &drm->outputs, link) {
|
wl_list_for_each(conn, &drm->outputs, link) {
|
||||||
if (search->crtc && search->crtc->id == crtc_id) {
|
if (conn->pending_page_flip_crtc == crtc_id) {
|
||||||
conn = search;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!conn) {
|
if (!found) {
|
||||||
wlr_log(WLR_DEBUG, "No connector for CRTC %u", crtc_id);
|
wlr_log(WLR_DEBUG, "Unexpected page-flip event for CRTC %u", crtc_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
conn->pageflip_pending = false;
|
conn->pending_page_flip_crtc = 0;
|
||||||
|
|
||||||
if (conn->state != WLR_DRM_CONN_CONNECTED || conn->crtc == NULL) {
|
if (conn->state != WLR_DRM_CONN_CONNECTED || conn->crtc == NULL) {
|
||||||
|
wlr_drm_conn_log(conn, WLR_DEBUG,
|
||||||
|
"Ignoring page-flip event for disabled connector");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1529,7 +1532,7 @@ void restore_drm_outputs(struct wlr_drm_backend *drm) {
|
||||||
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) {
|
||||||
if (conn->state != WLR_DRM_CONN_CLEANUP || !conn->pageflip_pending) {
|
if (conn->state != WLR_DRM_CONN_CLEANUP || !conn->pending_page_flip_crtc) {
|
||||||
to_close &= ~(UINT64_C(1) << i);
|
to_close &= ~(UINT64_C(1) << i);
|
||||||
}
|
}
|
||||||
i++;
|
i++;
|
||||||
|
|
|
@ -129,13 +129,14 @@ struct wlr_drm_connector {
|
||||||
|
|
||||||
struct wl_list link;
|
struct wl_list link;
|
||||||
|
|
||||||
/*
|
/* CRTC ID if a page-flip is pending, zero otherwise.
|
||||||
|
*
|
||||||
* We've asked for a state change in the kernel, and yet to receive a
|
* We've asked for a state change in the kernel, and yet to receive a
|
||||||
* notification for its completion. Currently, the kernel only has a
|
* notification for its completion. Currently, the kernel only has a
|
||||||
* queue length of 1, and no way to modify your submissions after
|
* queue length of 1, and no way to modify your submissions after
|
||||||
* they're sent.
|
* they're sent.
|
||||||
*/
|
*/
|
||||||
bool pageflip_pending;
|
uint32_t pending_page_flip_crtc;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct wlr_drm_backend *get_drm_backend_from_backend(
|
struct wlr_drm_backend *get_drm_backend_from_backend(
|
||||||
|
|
Loading…
Reference in a new issue