From 44ba603c0ef5ee05e89e7021c7df8061b3d5f56b Mon Sep 17 00:00:00 2001 From: Simon Ser Date: Sat, 4 May 2019 12:07:37 +0300 Subject: [PATCH] backend/drm: hold buffers while scanning out --- backend/drm/drm.c | 30 +++++++++++++++++++++++++----- include/backend/drm/drm.h | 5 +++++ 2 files changed, 30 insertions(+), 5 deletions(-) diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 37116af8..70a1edde 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -350,6 +350,11 @@ static bool drm_connector_commit(struct wlr_output *output) { } conn->pageflip_pending = true; + if (output->pending.buffer_type == WLR_OUTPUT_STATE_BUFFER_SCANOUT) { + wlr_buffer_unref(conn->pending_buffer); + conn->pending_buffer = wlr_buffer_ref(output->pending.buffer); + } + wlr_output_update_enabled(output, true); return true; } @@ -1440,9 +1445,21 @@ static void page_flip_handler(int fd, unsigned seq, return; } - post_drm_surface(&conn->crtc->primary->surf); - if (drm->parent) { - post_drm_surface(&conn->crtc->primary->mgpu_surf); + // Release the old buffer as it's not displayed anymore. The pending + // buffer becomes the current buffer. + wlr_buffer_unref(conn->current_buffer); + conn->current_buffer = conn->pending_buffer; + conn->pending_buffer = NULL; + + uint32_t present_flags = WLR_OUTPUT_PRESENT_VSYNC | + WLR_OUTPUT_PRESENT_HW_CLOCK | WLR_OUTPUT_PRESENT_HW_COMPLETION; + if (conn->current_buffer != NULL) { + present_flags |= WLR_OUTPUT_PRESENT_ZERO_COPY; + } else { + post_drm_surface(&conn->crtc->primary->surf); + if (drm->parent) { + post_drm_surface(&conn->crtc->primary->mgpu_surf); + } } struct timespec present_time = { @@ -1453,8 +1470,7 @@ static void page_flip_handler(int fd, unsigned seq, .when = &present_time, .seq = seq, .refresh = mhz_to_nsec(conn->output.refresh), - .flags = WLR_OUTPUT_PRESENT_VSYNC | WLR_OUTPUT_PRESENT_HW_CLOCK | - WLR_OUTPUT_PRESENT_HW_COMPLETION, + .flags = present_flags, }; wlr_output_send_present(&conn->output, &present_event); @@ -1559,6 +1575,10 @@ static void drm_connector_cleanup(struct wlr_drm_connector *conn) { conn->output.needs_frame = false; conn->output.frame_pending = false; + wlr_buffer_unref(conn->pending_buffer); + wlr_buffer_unref(conn->current_buffer); + conn->pending_buffer = conn->current_buffer = NULL; + /* Fallthrough */ case WLR_DRM_CONN_NEEDS_MODESET: wlr_log(WLR_INFO, "Emitting destruction signal for '%s'", diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index a20002b0..3821c358 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -149,7 +149,12 @@ struct wlr_drm_connector { struct wl_event_source *retry_pageflip; struct wl_list link; + // DMA-BUF to be displayed on next commit struct wlr_dmabuf_attributes pending_dmabuf; + // Buffer submitted to the kernel but not yet displayed + struct wlr_buffer *pending_buffer; + // Buffer currently being displayed + struct wlr_buffer *current_buffer; }; struct wlr_drm_backend *get_drm_backend_from_backend(