diff --git a/backend/drm/drm.c b/backend/drm/drm.c index 0f548f45..37116af8 100644 --- a/backend/drm/drm.c +++ b/backend/drm/drm.c @@ -301,11 +301,44 @@ static bool drm_connector_commit(struct wlr_output *output) { damage = &output->pending.damage; } - struct gbm_bo *bo = swap_drm_surface_buffers(&plane->surf, damage); - if (drm->parent) { - bo = copy_drm_surface_mgpu(&plane->mgpu_surf, bo); + struct gbm_bo *bo; + uint32_t fb_id = 0; + assert(output->pending.committed & WLR_OUTPUT_STATE_BUFFER); + switch (output->pending.buffer_type) { + case WLR_OUTPUT_STATE_BUFFER_RENDER: + bo = swap_drm_surface_buffers(&plane->surf, damage); + if (bo == NULL) { + wlr_log(WLR_ERROR, "swap_drm_surface_buffers failed"); + return false; + } + + if (drm->parent) { + bo = copy_drm_surface_mgpu(&plane->mgpu_surf, bo); + if (bo == NULL) { + wlr_log(WLR_ERROR, "copy_drm_surface_mgpu failed"); + return false; + } + } + fb_id = get_fb_for_bo(bo, plane->drm_format); + if (fb_id == 0) { + wlr_log(WLR_ERROR, "get_fb_for_bo failed"); + return false; + } + break; + case WLR_OUTPUT_STATE_BUFFER_SCANOUT: + bo = import_gbm_bo(&drm->renderer, &conn->pending_dmabuf); + if (bo == NULL) { + wlr_log(WLR_ERROR, "import_gbm_bo failed"); + return false; + } + + fb_id = get_fb_for_bo(bo, gbm_bo_get_format(bo)); + if (fb_id == 0) { + wlr_log(WLR_ERROR, "get_fb_for_bo failed"); + return false; + } + break; } - uint32_t fb_id = get_fb_for_bo(bo, plane->drm_format); if (conn->pageflip_pending) { wlr_log(WLR_ERROR, "Skipping pageflip on output '%s'", conn->output.name); @@ -903,30 +936,7 @@ static bool drm_connector_attach_buffer(struct wlr_output *output, } } - struct gbm_bo *bo = import_gbm_bo(&drm->renderer, &attribs); - if (bo == NULL) { - wlr_log(WLR_ERROR, "import_gbm_bo failed"); - return NULL; - } - - uint32_t fb_id = get_fb_for_bo(bo, gbm_bo_get_format(bo)); - if (fb_id == 0) { - wlr_log(WLR_ERROR, "get_fb_for_bo failed"); - return false; - } - - if (conn->pageflip_pending) { - wlr_log(WLR_ERROR, "Skipping pageflip on output '%s'", conn->output.name); - return false; - } - - if (!drm->iface->crtc_pageflip(drm, conn, crtc, fb_id, NULL)) { - wlr_log(WLR_ERROR, "crtc_pageflip failed"); - return false; - } - - conn->pageflip_pending = true; - wlr_output_update_enabled(output, true); + memcpy(&conn->pending_dmabuf, &attribs, sizeof(attribs)); return true; } diff --git a/include/backend/drm/drm.h b/include/backend/drm/drm.h index ba08449a..a20002b0 100644 --- a/include/backend/drm/drm.h +++ b/include/backend/drm/drm.h @@ -148,6 +148,8 @@ struct wlr_drm_connector { bool pageflip_pending; struct wl_event_source *retry_pageflip; struct wl_list link; + + struct wlr_dmabuf_attributes pending_dmabuf; }; struct wlr_drm_backend *get_drm_backend_from_backend( diff --git a/include/wlr/types/wlr_output.h b/include/wlr/types/wlr_output.h index ffe13fb8..cd05cfb4 100644 --- a/include/wlr/types/wlr_output.h +++ b/include/wlr/types/wlr_output.h @@ -52,12 +52,21 @@ enum wlr_output_state_field { WLR_OUTPUT_STATE_DAMAGE = 1 << 1, }; +enum wlr_output_state_buffer_type { + WLR_OUTPUT_STATE_BUFFER_RENDER, + WLR_OUTPUT_STATE_BUFFER_SCANOUT, +}; + /** * Holds the double-buffered output state. */ struct wlr_output_state { uint32_t committed; // enum wlr_output_state_field pixman_region32_t damage; // output-buffer-local coordinates + + // only valid if WLR_OUTPUT_STATE_BUFFER + enum wlr_output_state_buffer_type buffer_type; + struct wlr_buffer *buffer; // if WLR_OUTPUT_STATE_BUFFER_SCANOUT }; struct wlr_output_impl; diff --git a/types/wlr_output.c b/types/wlr_output.c index 389d4c1e..941d3ce8 100644 --- a/types/wlr_output.c +++ b/types/wlr_output.c @@ -404,6 +404,7 @@ bool wlr_output_attach_render(struct wlr_output *output, int *buffer_age) { } output->pending.committed |= WLR_OUTPUT_STATE_BUFFER; + output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_RENDER; return true; } @@ -480,15 +481,6 @@ bool wlr_output_commit(struct wlr_output *output) { bool wlr_output_attach_buffer(struct wlr_output *output, struct wlr_buffer *buffer) { - if (output->frame_pending) { - wlr_log(WLR_ERROR, "Tried to swap buffers when a frame is pending"); - return false; - } - if (output->idle_frame != NULL) { - wl_event_source_remove(output->idle_frame); - output->idle_frame = NULL; - } - if (!output->impl->attach_buffer) { return false; } @@ -496,9 +488,8 @@ bool wlr_output_attach_buffer(struct wlr_output *output, return false; } - output->frame_pending = true; - output->needs_frame = false; - pixman_region32_clear(&output->damage); + output->pending.committed |= WLR_OUTPUT_STATE_BUFFER; + output->pending.buffer_type = WLR_OUTPUT_STATE_BUFFER_SCANOUT; return true; }