drm-backend: address case in which writeback takes longer than atomic commit
In commit "drm-backend: add writeback connector screenshooter to DRM-backend" we were failing the writeback screenshot when the DRM/KMS driver would take longer than the atomic commit to finish. In this patch we address such case. Signed-off-by: Leandro Ribeiro <leandro.ribeiro@collabora.com>
This commit is contained in:
parent
5b04895835
commit
dc27a52216
@ -567,6 +567,12 @@ enum writeback_screenshot_state {
|
||||
* commit is handled by DRM it will give us a sync fd that gets
|
||||
* signalled when the writeback is done. */
|
||||
DRM_OUTPUT_WB_SCREENSHOT_CHECK_FENCE,
|
||||
/* The atomic commit completed and we received the sync fd from the
|
||||
* kernel. We've polled to check if the writeback was over, but it
|
||||
* wasn't. Now we must stop the repaint loop and wait until the
|
||||
* writeback is complete, because we can't commit with KMS objects
|
||||
* (CRTC, planes, etc) that are in used by the writeback job. */
|
||||
DRM_OUTPUT_WB_SCREENSHOT_WAITING_SIGNAL,
|
||||
};
|
||||
|
||||
struct drm_writeback_state {
|
||||
@ -578,6 +584,7 @@ struct drm_writeback_state {
|
||||
|
||||
struct drm_fb *fb;
|
||||
int32_t out_fence_fd;
|
||||
struct wl_event_source *wb_source;
|
||||
|
||||
/* Reference to fb's being used by the writeback job. These are all the
|
||||
* framebuffers in every drm_plane_state of the output state that we've
|
||||
@ -699,7 +706,7 @@ void
|
||||
drm_writeback_reference_planes(struct drm_writeback_state *state,
|
||||
struct wl_list *plane_state_list);
|
||||
bool
|
||||
drm_writeback_has_finished(struct drm_writeback_state *state);
|
||||
drm_writeback_should_wait_completion(struct drm_writeback_state *state);
|
||||
void
|
||||
drm_writeback_fail_screenshot(struct drm_writeback_state *state,
|
||||
const char *err_msg);
|
||||
|
@ -2670,7 +2670,20 @@ drm_writeback_fail_screenshot(struct drm_writeback_state *state,
|
||||
output->wb_state = NULL;
|
||||
}
|
||||
|
||||
bool
|
||||
static int
|
||||
drm_writeback_save_callback(int fd, uint32_t mask, void *data)
|
||||
{
|
||||
struct drm_writeback_state *state = data;
|
||||
|
||||
wl_event_source_remove(state->wb_source);
|
||||
close(fd);
|
||||
|
||||
drm_writeback_success_screenshot(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool
|
||||
drm_writeback_has_finished(struct drm_writeback_state *state)
|
||||
{
|
||||
struct pollfd pollfd;
|
||||
@ -2695,6 +2708,40 @@ drm_writeback_has_finished(struct drm_writeback_state *state)
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
drm_writeback_should_wait_completion(struct drm_writeback_state *state)
|
||||
{
|
||||
struct weston_compositor *ec = state->output->base.compositor;
|
||||
struct wl_event_loop *event_loop;
|
||||
|
||||
if (state->state == DRM_OUTPUT_WB_SCREENSHOT_WAITING_SIGNAL)
|
||||
return true;
|
||||
|
||||
if (state->state == DRM_OUTPUT_WB_SCREENSHOT_CHECK_FENCE) {
|
||||
if (drm_writeback_has_finished(state))
|
||||
return false;
|
||||
|
||||
/* The writeback has not finished yet. So add callback that gets
|
||||
* called when the sync fd of the writeback job gets signalled.
|
||||
* We need to wait for that to resume the repaint loop. */
|
||||
event_loop = wl_display_get_event_loop(ec->wl_display);
|
||||
state->wb_source =
|
||||
wl_event_loop_add_fd(event_loop, state->out_fence_fd,
|
||||
WL_EVENT_READABLE,
|
||||
drm_writeback_save_callback, state);
|
||||
if (!state->wb_source) {
|
||||
drm_writeback_fail_screenshot(state, "drm: out of memory");
|
||||
return false;
|
||||
}
|
||||
|
||||
state->state = DRM_OUTPUT_WB_SCREENSHOT_WAITING_SIGNAL;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
drm_writeback_reference_planes(struct drm_writeback_state *state,
|
||||
struct wl_list *plane_state_list)
|
||||
|
@ -1750,6 +1750,7 @@ on_drm_input(int fd, uint32_t mask, void *data)
|
||||
struct drm_device *device = data;
|
||||
struct drm_writeback_state *state;
|
||||
struct drm_crtc *crtc;
|
||||
bool wait_wb_completion = false;
|
||||
drmEventContext evctx;
|
||||
|
||||
/* If we have a pending writeback job for this output, we can't continue
|
||||
@ -1758,9 +1759,11 @@ on_drm_input(int fd, uint32_t mask, void *data)
|
||||
* uses the KMS objects (CRTC, planes, etc) in use by the writeback. */
|
||||
wl_list_for_each(crtc, &device->crtc_list, link) {
|
||||
state = crtc->output ? crtc->output->wb_state : NULL;
|
||||
if (state && !drm_writeback_has_finished(state))
|
||||
drm_writeback_fail_screenshot(state, "drm: out fence not signalled yet");
|
||||
if (state && drm_writeback_should_wait_completion(state))
|
||||
wait_wb_completion = true;
|
||||
}
|
||||
if (wait_wb_completion)
|
||||
return 1;
|
||||
|
||||
memset(&evctx, 0, sizeof evctx);
|
||||
evctx.version = 3;
|
||||
|
Loading…
x
Reference in New Issue
Block a user