summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--man/armada.man12
-rw-r--r--src/armada_drm.c1
-rw-r--r--src/armada_drm.h1
-rw-r--r--src/armada_drm_xv.c80
4 files changed, 93 insertions, 1 deletions
diff --git a/man/armada.man b/man/armada.man
index 94acc3f..8e2acab 100644
--- a/man/armada.man
+++ b/man/armada.man
@@ -120,6 +120,18 @@ Enable or disable the X Video backend.
.IP
Default: enabled.
.TP
+.BI "Option \*qXvDisablePrimary\*q \*q" boolean \*q
+Allow the X Video backend to disable the primary plane when X Video
+image is displayed at full screen.
+.IP
+.B Note:
+Some kernel drivers may not fully support this (eg, the kernel driver
+does a full modeset when restoring the primary plane, causing the
+screen to momentarily blank.) This option should be disabled for such
+kernel drivers, or the kernel driver updated to avoid such behaviour.
+.IP
+Default: enabled.
+.TP
.BI "Option \*qXvPreferOverlay\*q \*q" boolean \*q
Make the hardware overlay the first XV adapter. Disabling this option
makes any GPU provided textured overlay the first XV adapter.
diff --git a/src/armada_drm.c b/src/armada_drm.c
index 0f21493..567350d 100644
--- a/src/armada_drm.c
+++ b/src/armada_drm.c
@@ -36,6 +36,7 @@
const OptionInfoRec armada_drm_options[] = {
{ OPTION_XV_ACCEL, "XvAccel", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_XV_PREFEROVL, "XvPreferOverlay", OPTV_BOOLEAN, {0}, TRUE },
+ { OPTION_XV_DISPRIMARY, "XvDisablePrimary",OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_USE_GPU, "UseGPU", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_USE_KMS_BO, "UseKMSBo", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ACCEL_MODULE, "AccelModule", OPTV_STRING, {0}, FALSE },
diff --git a/src/armada_drm.h b/src/armada_drm.h
index ec60e73..f9a3fae 100644
--- a/src/armada_drm.h
+++ b/src/armada_drm.h
@@ -38,6 +38,7 @@ struct all_drm_info {
enum {
OPTION_XV_ACCEL,
OPTION_XV_PREFEROVL,
+ OPTION_XV_DISPRIMARY,
OPTION_USE_GPU,
OPTION_USE_KMS_BO,
OPTION_ACCEL_MODULE,
diff --git a/src/armada_drm_xv.c b/src/armada_drm_xv.c
index 5302ac6..52c9c05 100644
--- a/src/armada_drm_xv.c
+++ b/src/armada_drm_xv.c
@@ -65,6 +65,8 @@ struct drm_xv {
Bool has_xvbo;
Bool is_xvbo;
Bool autopaint_colorkey;
+ Bool has_primary;
+ Bool primary_obscured;
/* Cached image information */
RegionRec clipBoxes;
@@ -91,9 +93,10 @@ struct drm_xv {
/* Plane information */
const struct xv_image_format *plane_format;
uint32_t plane_fb_id;
+ xf86CrtcPtr primary_crtc;
drmModePlanePtr overlay_plane;
unsigned int num_planes;
- drmModePlanePtr mode_planes[2];
+ drmModePlanePtr mode_planes[4];
struct drm_xv_prop props[NR_DRM_PROPS];
};
@@ -780,6 +783,41 @@ armada_drm_plane_fbid(ScrnInfoPtr pScrn, struct drm_xv *drmxv, int image,
return Success;
}
+static void armada_drm_primary_plane_restore(xf86CrtcPtr crtc)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(crtc->scrn);
+ struct common_crtc_info *drmc = common_crtc(crtc);
+ int ret;
+
+ ret = drmModeSetPlane(drm->fd, drmc->primary_plane_id,
+ drmc->mode_crtc->crtc_id, drm->fb_id, 0,
+ crtc->x, crtc->y,
+ crtc->mode.HDisplay, crtc->mode.VDisplay,
+ 0, 0,
+ crtc->mode.HDisplay << 16,
+ crtc->mode.VDisplay << 16);
+ if (ret)
+ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
+ "[drm] unable to restore plane %u: %s\n",
+ drmc->primary_plane_id, strerror(errno));
+}
+
+static Bool armada_drm_primary_plane_disable(xf86CrtcPtr crtc)
+{
+ struct common_drm_info *drm = GET_DRM_INFO(crtc->scrn);
+ struct common_crtc_info *drmc = common_crtc(crtc);
+ int ret;
+
+ ret = drmModeSetPlane(drm->fd, drmc->primary_plane_id,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0);
+ if (ret)
+ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
+ "[drm] unable to disable plane %u: %s\n",
+ drmc->primary_plane_id, strerror(errno));
+
+ return ret == 0;
+}
+
static void armada_drm_plane_disable(ScrnInfoPtr pScrn, struct drm_xv *drmxv,
drmModePlanePtr mode_plane)
{
@@ -798,6 +836,11 @@ armada_drm_plane_StopVideo(ScrnInfoPtr pScrn, pointer data, Bool cleanup)
{
struct drm_xv *drmxv = data;
+ if (drmxv->primary_crtc) {
+ armada_drm_primary_plane_restore(drmxv->primary_crtc);
+ drmxv->primary_crtc = NULL;
+ }
+
if (drmxv->overlay_plane) {
RegionEmpty(&drmxv->clipBoxes);
armada_drm_plane_disable(pScrn, drmxv, drmxv->overlay_plane);
@@ -824,6 +867,13 @@ static Bool armada_drm_check_plane(ScrnInfoPtr pScrn, struct drm_xv *drmxv,
crtc_mask = 1 << common_crtc(crtc)->num;
+ if (drmxv->primary_crtc && drmxv->primary_crtc != crtc) {
+ /* Moved to a different CRTC */
+ armada_drm_primary_plane_restore(drmxv->primary_crtc);
+ drmxv->primary_crtc = NULL;
+ drmxv->primary_obscured = FALSE;
+ }
+
if (drmxv->overlay_plane &&
!(drmxv->overlay_plane->possible_crtcs & crtc_mask)) {
/* Moved on to a different CRTC */
@@ -888,6 +938,29 @@ armada_drm_plane_Put(ScrnInfoPtr pScrn, struct drm_xv *drmxv, uint32_t fb_id,
crtc_x, crtc_y, dst->x2 - dst->x1, dst->y2 - dst->y1,
x1, y1, x2 - x1, y2 - y1);
+ if (drmxv->has_primary) {
+ BoxRec crtcbox;
+ Bool obscured;
+
+ crtcbox.x1 = crtc->x;
+ crtcbox.y1 = crtc->y;
+ crtcbox.x2 = crtc->x + crtc->mode.HDisplay;
+ crtcbox.y2 = crtc->y + crtc->mode.VDisplay;
+
+ obscured = RegionContainsRect(clipBoxes, &crtcbox) == rgnIN;
+
+ if (obscured && !drmxv->primary_obscured) {
+ if (common_crtc(crtc)->primary_plane_id &&
+ armada_drm_primary_plane_disable(crtc))
+ drmxv->primary_crtc = crtc;
+ } else if (!obscured && drmxv->primary_crtc) {
+ armada_drm_primary_plane_restore(drmxv->primary_crtc);
+ drmxv->primary_crtc = NULL;
+ }
+
+ drmxv->primary_obscured = obscured;
+ }
+
return Success;
}
@@ -1129,6 +1202,8 @@ static Bool armada_drm_gather_planes(ScrnInfoPtr pScrn, struct drm_xv *drmxv)
if (!common_drm_init_plane_resources(pScrn))
return FALSE;
+ drmxv->has_primary = drm->has_universal_planes;
+
for (i = 0; i < drm->num_overlay_planes &&
i < ARRAY_SIZE(drmxv->mode_planes); i++) {
drmxv->mode_planes[drmxv->num_planes++] =
@@ -1181,6 +1256,9 @@ Bool armada_drm_XvInit(ScrnInfoPtr pScrn)
if (!armada_drm_gather_planes(pScrn, drmxv))
goto err_free;
+ if (!xf86ReturnOptValBool(arm->Options, OPTION_XV_DISPRIMARY, TRUE))
+ drmxv->has_primary = FALSE;
+
prefer_overlay = xf86ReturnOptValBool(arm->Options,
OPTION_XV_PREFEROVL, TRUE);