diff options
author | Louis-Francis Ratté-Boulianne <lfrb@collabora.com> | 2018-04-04 00:01:15 -0400 |
---|---|---|
committer | Adam Jackson <ajax@redhat.com> | 2018-04-04 14:01:51 -0400 |
commit | 44e7098367b87c79470d6760753e42014be7ca01 (patch) | |
tree | 81af59ab245836c15ac3db8a28ecc7688751c386 | |
parent | bc4d278132956ec3c43695f1bd34083ef5fe7f22 (diff) |
modesetting: Have consistent state when using atomic modesetting
We need to make sure that the atomic commit are consistent
or else the kernel will reject it. For example, when moving
a CRTC from one output to another one, the first output CRTC_ID
property needs to be reset. Also if the second output was using
another CRTC beforehands, it needs to be disabled to avoid an
inconsistent state.
Signed-off-by: Louis-Francis Ratté-Boulianne <lfrb@collabora.com>
Tested-by: Daniel Stone <daniels@collabora.com>
Reviewed-by: Adam Jackson <ajax@redhat.com>
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.c | 66 | ||||
-rw-r--r-- | hw/xfree86/drivers/modesetting/drmmode_display.h | 1 |
2 files changed, 64 insertions, 3 deletions
diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.c b/hw/xfree86/drivers/modesetting/drmmode_display.c index 756aa45c8..de493f903 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.c +++ b/hw/xfree86/drivers/modesetting/drmmode_display.c @@ -529,12 +529,16 @@ crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc, for (i = 0; i < xf86_config->num_output; i++) { xf86OutputPtr output = xf86_config->output[i]; - drmmode_output_private_ptr drmmode_output; + drmmode_output_private_ptr drmmode_output = output->driver_private; - if (output->crtc != crtc) + if (output->crtc != crtc) { + if (drmmode_output->current_crtc == crtc) { + ret |= connector_add_prop(req, drmmode_output, + DRMMODE_CONNECTOR_CRTC_ID, 0); + } continue; + } - drmmode_output = output->driver_private; if (drmmode_output->output_id == -1) continue; @@ -644,6 +648,17 @@ drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags) if (!req) return; + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output = output->driver_private; + + if (output->crtc != NULL) + continue; + + ret = connector_add_prop(req, drmmode_output, + DRMMODE_CONNECTOR_CRTC_ID, 0); + } + for (i = 0; i < xf86_config->num_crtc; i++) { xf86CrtcPtr crtc = xf86_config->crtc[i]; drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; @@ -691,6 +706,9 @@ drmmode_output_disable(xf86OutputPtr output) if (ret == 0) ret = drmModeAtomicCommit(ms->fd, req, flags, NULL); + if (ret == 0) + drmmode_output->current_crtc = NULL; + drmModeAtomicFree(req); return ret; } @@ -749,12 +767,54 @@ drmmode_crtc_set_mode(xf86CrtcPtr crtc, Bool test_only) ret |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active); ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y); + /* Orphaned CRTCs need to be disabled right now in atomic mode */ + for (i = 0; i < xf86_config->num_crtc; i++) { + xf86CrtcPtr other_crtc = xf86_config->crtc[i]; + drmmode_crtc_private_ptr other_drmmode_crtc = other_crtc->driver_private; + int lost_outputs = 0; + int remaining_outputs = 0; + + if (other_crtc == crtc) + continue; + + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output = output->driver_private; + + if (drmmode_output->current_crtc == other_crtc) { + if (output->crtc == crtc) + lost_outputs++; + else + remaining_outputs++; + } + } + + if (lost_outputs > 0 && remaining_outputs == 0) { + ret |= crtc_add_prop(req, other_drmmode_crtc, + DRMMODE_CRTC_ACTIVE, 0); + ret |= crtc_add_prop(req, other_drmmode_crtc, + DRMMODE_CRTC_MODE_ID, 0); + } + } + if (test_only) flags |= DRM_MODE_ATOMIC_TEST_ONLY; if (ret == 0) ret = drmModeAtomicCommit(ms->fd, req, flags, NULL); + if (ret == 0 && !test_only) { + for (i = 0; i < xf86_config->num_output; i++) { + xf86OutputPtr output = xf86_config->output[i]; + drmmode_output_private_ptr drmmode_output = output->driver_private; + + if (output->crtc == crtc) + drmmode_output->current_crtc = crtc; + else if (drmmode_output->current_crtc == crtc) + drmmode_output->current_crtc = NULL; + } + } + drmModeAtomicFree(req); return ret; } diff --git a/hw/xfree86/drivers/modesetting/drmmode_display.h b/hw/xfree86/drivers/modesetting/drmmode_display.h index a75576926..74954b853 100644 --- a/hw/xfree86/drivers/modesetting/drmmode_display.h +++ b/hw/xfree86/drivers/modesetting/drmmode_display.h @@ -213,6 +213,7 @@ typedef struct { drmmode_prop_info_rec props_connector[DRMMODE_CONNECTOR__COUNT]; int enc_mask; int enc_clone_mask; + xf86CrtcPtr current_crtc; } drmmode_output_private_rec, *drmmode_output_private_ptr; typedef struct { |