From 7beee68f8d8617557990a5f860d9d1f99c4ba009 Mon Sep 17 00:00:00 2001 From: Anton Kindestam Date: Sat, 2 Jun 2018 12:53:54 +0200 Subject: context_drm_egl: Fix CRTC setup and release code when using atomic The previous code did not save enough information about the old state, and could end up changing what plane the fbcon:s FB got attached to, or in worse case causing a blank screen (observed in some multi-screen setups on Sandy Bridge). In addition refactor the handling of drmModeModeInfo property blobs to not leak, as well as enable reuse of already created blobs. --- video/out/drm_atomic.c | 144 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 144 insertions(+) (limited to 'video/out/drm_atomic.c') diff --git a/video/out/drm_atomic.c b/video/out/drm_atomic.c index 8e68cdb074..5c6b3bbe21 100644 --- a/video/out/drm_atomic.c +++ b/video/out/drm_atomic.c @@ -290,9 +290,153 @@ fail: void drm_atomic_destroy_context(struct drm_atomic_context *ctx) { + drm_mode_destroy_blob(ctx->fd, &ctx->old_state.crtc.mode); drm_object_free(ctx->crtc); drm_object_free(ctx->connector); drm_object_free(ctx->osd_plane); drm_object_free(ctx->video_plane); talloc_free(ctx); } + +static bool drm_atomic_save_plane_state(struct drm_object *plane, + struct drm_atomic_plane_state *plane_state) +{ + bool ret = true; + + if (0 > drm_object_get_property(plane, "FB_ID", &plane_state->fb_id)) + ret = false; + if (0 > drm_object_get_property(plane, "CRTC_ID", &plane_state->crtc_id)) + ret = false; + if (0 > drm_object_get_property(plane, "SRC_X", &plane_state->src_x)) + ret = false; + if (0 > drm_object_get_property(plane, "SRC_Y", &plane_state->src_y)) + ret = false; + if (0 > drm_object_get_property(plane, "SRC_W", &plane_state->src_w)) + ret = false; + if (0 > drm_object_get_property(plane, "SRC_H", &plane_state->src_h)) + ret = false; + if (0 > drm_object_get_property(plane, "CRTC_X", &plane_state->crtc_x)) + ret = false; + if (0 > drm_object_get_property(plane, "CRTC_Y", &plane_state->crtc_y)) + ret = false; + if (0 > drm_object_get_property(plane, "CRTC_W", &plane_state->crtc_w)) + ret = false; + if (0 > drm_object_get_property(plane, "CRTC_H", &plane_state->crtc_h)) + ret = false; + // ZPOS might not exist, so ignore whether or not this succeeds + drm_object_get_property(plane, "ZPOS", &plane_state->zpos); + + return ret; +} + +static bool drm_atomic_restore_plane_state(drmModeAtomicReq *request, + struct drm_object *plane, + const struct drm_atomic_plane_state *plane_state) +{ + bool ret = true; + + if (0 > drm_object_set_property(request, plane, "FB_ID", plane_state->fb_id)) + ret = false; + if (0 > drm_object_set_property(request, plane, "CRTC_ID", plane_state->crtc_id)) + ret = false; + if (0 > drm_object_set_property(request, plane, "SRC_X", plane_state->src_x)) + ret = false; + if (0 > drm_object_set_property(request, plane, "SRC_Y", plane_state->src_y)) + ret = false; + if (0 > drm_object_set_property(request, plane, "SRC_W", plane_state->src_w)) + ret = false; + if (0 > drm_object_set_property(request, plane, "SRC_H", plane_state->src_h)) + ret = false; + if (0 > drm_object_set_property(request, plane, "CRTC_X", plane_state->crtc_x)) + ret = false; + if (0 > drm_object_set_property(request, plane, "CRTC_Y", plane_state->crtc_y)) + ret = false; + if (0 > drm_object_set_property(request, plane, "CRTC_W", plane_state->crtc_w)) + ret = false; + if (0 > drm_object_set_property(request, plane, "CRTC_H", plane_state->crtc_h)) + ret = false; + // ZPOS might not exist, so ignore whether or not this succeeds + drm_object_set_property(request, plane, "ZPOS", plane_state->zpos); + + return ret; +} + +bool drm_atomic_save_old_state(struct drm_atomic_context *ctx) +{ + if (ctx->old_state.saved) + return false; + + bool ret = true; + + drmModeCrtc *crtc = drmModeGetCrtc(ctx->fd, ctx->crtc->id); + if (crtc == NULL) + return false; + ctx->old_state.crtc.mode.mode = crtc->mode; + drmModeFreeCrtc(crtc); + + if (0 > drm_object_get_property(ctx->crtc, "ACTIVE", &ctx->old_state.crtc.active)) + ret = false; + + if (0 > drm_object_get_property(ctx->connector, "CRTC_ID", &ctx->old_state.connector.crtc_id)) + ret = false; + + if (!drm_atomic_save_plane_state(ctx->osd_plane, &ctx->old_state.osd_plane)) + ret = false; + if (!drm_atomic_save_plane_state(ctx->video_plane, &ctx->old_state.video_plane)) + ret = false; + + ctx->old_state.saved = true; + + return ret; +} + +bool drm_atomic_restore_old_state(drmModeAtomicReqPtr request, struct drm_atomic_context *ctx) +{ + if (!ctx->old_state.saved) + return false; + + bool ret = true; + + if (0 > drm_object_set_property(request, ctx->connector, "CRTC_ID", ctx->old_state.connector.crtc_id)) + ret = false; + + if (!drm_mode_ensure_blob(ctx->fd, &ctx->old_state.crtc.mode)) + ret = false; + if (0 > drm_object_set_property(request, ctx->crtc, "MODE_ID", ctx->old_state.crtc.mode.blob_id)) + ret = false; + if (0 > drm_object_set_property(request, ctx->crtc, "ACTIVE", ctx->old_state.crtc.active)) + ret = false; + + if (!drm_atomic_restore_plane_state(request, ctx->osd_plane, &ctx->old_state.osd_plane)) + ret = false; + if (!drm_atomic_restore_plane_state(request, ctx->video_plane, &ctx->old_state.video_plane)) + ret = false; + + ctx->old_state.saved = false; + + return ret; +} + +bool drm_mode_ensure_blob(int fd, struct drm_mode *mode) +{ + int ret = 0; + + if (!mode->blob_id) { + ret = drmModeCreatePropertyBlob(fd, &mode->mode, sizeof(drmModeModeInfo), + &mode->blob_id); + } + + return (ret == 0); +} + +bool drm_mode_destroy_blob(int fd, struct drm_mode *mode) +{ + int ret = 0; + + if (mode->blob_id) { + ret = drmModeDestroyPropertyBlob(fd, mode->blob_id); + mode->blob_id = 0; + } + + return (ret == 0); +} -- cgit v1.2.3