mirror of
				https://gitlab.freedesktop.org/wlroots/wlroots.git
				synced 2025-11-03 09:01:40 -05: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…
	
	Add table
		Add a link
		
	
		Reference in a new issue