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>
This commit is contained in:
parent
bc4d278132
commit
44e7098367
|
@ -529,12 +529,16 @@ crtc_add_dpms_props(drmModeAtomicReq *req, xf86CrtcPtr crtc,
|
||||||
|
|
||||||
for (i = 0; i < xf86_config->num_output; i++) {
|
for (i = 0; i < xf86_config->num_output; i++) {
|
||||||
xf86OutputPtr output = xf86_config->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;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
drmmode_output = output->driver_private;
|
|
||||||
if (drmmode_output->output_id == -1)
|
if (drmmode_output->output_id == -1)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
@ -644,6 +648,17 @@ drmmode_set_dpms(ScrnInfoPtr scrn, int dpms, int flags)
|
||||||
if (!req)
|
if (!req)
|
||||||
return;
|
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++) {
|
for (i = 0; i < xf86_config->num_crtc; i++) {
|
||||||
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
xf86CrtcPtr crtc = xf86_config->crtc[i];
|
||||||
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
|
||||||
|
@ -691,6 +706,9 @@ drmmode_output_disable(xf86OutputPtr output)
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
|
ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
|
||||||
|
|
||||||
|
if (ret == 0)
|
||||||
|
drmmode_output->current_crtc = NULL;
|
||||||
|
|
||||||
drmModeAtomicFree(req);
|
drmModeAtomicFree(req);
|
||||||
return ret;
|
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 |= crtc_add_dpms_props(req, crtc, DPMSModeOn, &active);
|
||||||
ret |= plane_add_props(req, crtc, active ? fb_id : 0, x, y);
|
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)
|
if (test_only)
|
||||||
flags |= DRM_MODE_ATOMIC_TEST_ONLY;
|
flags |= DRM_MODE_ATOMIC_TEST_ONLY;
|
||||||
|
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
ret = drmModeAtomicCommit(ms->fd, req, flags, NULL);
|
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);
|
drmModeAtomicFree(req);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
|
@ -213,6 +213,7 @@ typedef struct {
|
||||||
drmmode_prop_info_rec props_connector[DRMMODE_CONNECTOR__COUNT];
|
drmmode_prop_info_rec props_connector[DRMMODE_CONNECTOR__COUNT];
|
||||||
int enc_mask;
|
int enc_mask;
|
||||||
int enc_clone_mask;
|
int enc_clone_mask;
|
||||||
|
xf86CrtcPtr current_crtc;
|
||||||
} drmmode_output_private_rec, *drmmode_output_private_ptr;
|
} drmmode_output_private_rec, *drmmode_output_private_ptr;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
|
|
Loading…
Reference in New Issue