summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2015-12-25 18:57:42 +0900
committerMichel Dänzer <michel@daenzer.net>2016-03-09 16:11:47 +0900
commit798c4fd16d339b1ad5fd729cc884be084c60e38b (patch)
tree3548d868aba978aa69ecb4d06cd4d7f16967503f
parenteb611a2e4ecce7a1ab85fd72b9b78e3269311dd5 (diff)
Make Option "TearFree" effective for rotated/reflected outputs as well (v2)
Support varies by xserver version: < 1.12: No support for the driver handling rotation/reflection 1.12-1.15: Support for driver handling rotation/reflection, but there's a bug preventing the HW cursor from being visible everywhere it should be on rotated outputs, so we can only support TearFree for reflection. >= 1.16: While the bug above is still there (fixes pending review), the driver can force SW cursor for rotated outputs, so we can support TearFree for rotation as well. v2: Don't set crtc->driverIsPerformingTransform after xf86CrtcRotate if it wasn't set before. Fixes breaking rotation with TearFree disabled. Reviewed-by: Alex Deucher <alexander.deucher@amd.com> (v1)
-rw-r--r--src/drmmode_display.c132
-rw-r--r--src/radeon_kms.c123
2 files changed, 214 insertions, 41 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index cc71dd09..80fbbf6f 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -617,6 +617,34 @@ radeon_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
damage->damage.data = NULL;
}
+#if XF86_CRTC_VERSION >= 4
+
+static Bool
+drmmode_handle_transform(xf86CrtcPtr crtc)
+{
+ RADEONInfoPtr info = RADEONPTR(crtc->scrn);
+ Bool ret;
+
+ crtc->driverIsPerformingTransform = info->tear_free &&
+ !crtc->transformPresent && crtc->rotation != RR_Rotate_0;
+
+ ret = xf86CrtcRotate(crtc);
+
+ crtc->driverIsPerformingTransform &= ret && crtc->transform_in_use;
+
+ return ret;
+}
+
+#else
+
+static Bool
+drmmode_handle_transform(xf86CrtcPtr crtc)
+{
+ return xf86CrtcRotate(crtc);
+}
+
+#endif
+
static Bool
drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
Rotation rotation, int x, int y)
@@ -694,9 +722,9 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
output_count++;
}
- if (!xf86CrtcRotate(crtc)) {
+ if (!drmmode_handle_transform(crtc))
goto done;
- }
+
crtc->funcs->gamma_set(crtc, crtc->gamma_red, crtc->gamma_green,
crtc->gamma_blue, crtc->gamma_size);
@@ -718,7 +746,8 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[0]);
drmmode_crtc_scanout_destroy(drmmode, &drmmode_crtc->scanout[1]);
- } else if (info->tear_free || info->shadow_primary) {
+ } else if (info->tear_free || info->shadow_primary ||
+ crtc->driverIsPerformingTransform) {
for (i = 0; i < (info->tear_free ? 2 : 1); i++) {
drmmode_crtc_scanout_create(crtc,
&drmmode_crtc->scanout[i],
@@ -744,8 +773,17 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
pBox = RegionExtents(pRegion);
pBox->x1 = min(pBox->x1, x);
pBox->y1 = min(pBox->y1, y);
- pBox->x2 = max(pBox->x2, x + mode->HDisplay);
- pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+
+ switch (crtc->rotation & 0xf) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ pBox->x2 = max(pBox->x2, x + mode->VDisplay);
+ pBox->y2 = max(pBox->y2, y + mode->HDisplay);
+ break;
+ default:
+ pBox->x2 = max(pBox->x2, x + mode->HDisplay);
+ pBox->y2 = max(pBox->y2, y + mode->VDisplay);
+ }
}
}
@@ -821,24 +859,89 @@ drmmode_set_cursor_position (xf86CrtcPtr crtc, int x, int y)
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
+#if XF86_CRTC_VERSION >= 4
+ if (crtc->driverIsPerformingTransform) {
+ x += crtc->x;
+ y += crtc->y;
+ xf86CrtcTransformCursorPos(crtc, &x, &y);
+ }
+#endif
+
drmModeMoveCursor(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id, x, y);
}
+#if XF86_CRTC_VERSION >= 4
+
+static int
+drmmode_cursor_src_offset(Rotation rotation, int width, int height,
+ int x_dst, int y_dst)
+{
+ int t;
+
+ switch (rotation & 0xf) {
+ case RR_Rotate_90:
+ t = x_dst;
+ x_dst = height - y_dst - 1;
+ y_dst = t;
+ break;
+ case RR_Rotate_180:
+ x_dst = width - x_dst - 1;
+ y_dst = height - y_dst - 1;
+ break;
+ case RR_Rotate_270:
+ t = x_dst;
+ x_dst = y_dst;
+ y_dst = width - t - 1;
+ break;
+ }
+
+ if (rotation & RR_Reflect_X)
+ x_dst = width - x_dst - 1;
+ if (rotation & RR_Reflect_Y)
+ y_dst = height - y_dst - 1;
+
+ return y_dst * height + x_dst;
+}
+
+#endif
+
static void
drmmode_load_cursor_argb (xf86CrtcPtr crtc, CARD32 *image)
{
ScrnInfoPtr pScrn = crtc->scrn;
RADEONInfoPtr info = RADEONPTR(pScrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
- int i;
uint32_t *ptr;
- uint32_t cursor_size = info->cursor_w * info->cursor_h;
/* cursor should be mapped already */
ptr = (uint32_t *)(drmmode_crtc->cursor_bo->ptr);
- for (i = 0; i < cursor_size; i++)
- ptr[i] = cpu_to_le32(image[i]);
+#if XF86_CRTC_VERSION >= 4
+ if (crtc->driverIsPerformingTransform) {
+ uint32_t cursor_w = info->cursor_w, cursor_h = info->cursor_h;
+ int dstx, dsty;
+ int srcoffset;
+
+ for (dsty = 0; dsty < cursor_h; dsty++) {
+ for (dstx = 0; dstx < cursor_w; dstx++) {
+ srcoffset = drmmode_cursor_src_offset(crtc->rotation,
+ cursor_w,
+ cursor_h,
+ dstx, dsty);
+
+ ptr[dsty * info->cursor_w + dstx] =
+ cpu_to_le32(image[srcoffset]);
+ }
+ }
+ } else
+#endif
+ {
+ uint32_t cursor_size = info->cursor_w * info->cursor_h;
+ int i;
+
+ for (i = 0; i < cursor_size; i++)
+ ptr[i] = cpu_to_le32(image[i]);
+ }
}
#if XORG_VERSION_CURRENT >= XORG_VERSION_NUMERIC(1,15,99,903,0)
@@ -849,6 +952,13 @@ static Bool drmmode_load_cursor_argb_check(xf86CrtcPtr crtc, CARD32 * image)
if (crtc->transformPresent)
return FALSE;
+ /* Xorg doesn't correctly handle cursor position transform in the
+ * rotation case
+ */
+ if (crtc->driverIsPerformingTransform &&
+ (crtc->rotation & 0xf) != RR_Rotate_0)
+ return FALSE;
+
drmmode_load_cursor_argb(crtc, image);
return TRUE;
}
@@ -2276,8 +2386,8 @@ Bool drmmode_set_desired_modes(ScrnInfoPtr pScrn, drmmode_ptr drmmode,
crtc->rotation = crtc->desiredRotation;
crtc->x = crtc->desiredX;
crtc->y = crtc->desiredY;
- if (!xf86CrtcRotate(crtc))
- return FALSE;
+ if (!drmmode_handle_transform(crtc))
+ return FALSE;
}
}
return TRUE;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 44fe71e1..8048c95f 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -334,12 +334,22 @@ radeon_dirty_update(ScreenPtr screen)
#endif
static Bool
-radeon_scanout_extents_intersect(BoxPtr extents, int x, int y, int w, int h)
+radeon_scanout_extents_intersect(xf86CrtcPtr xf86_crtc, BoxPtr extents, int w,
+ int h)
{
- extents->x1 = max(extents->x1 - x, 0);
- extents->y1 = max(extents->y1 - y, 0);
- extents->x2 = min(extents->x2 - x, w);
- extents->y2 = min(extents->y2 - y, h);
+ extents->x1 = max(extents->x1 - xf86_crtc->x, 0);
+ extents->y1 = max(extents->y1 - xf86_crtc->y, 0);
+
+ switch (xf86_crtc->rotation & 0xf) {
+ case RR_Rotate_90:
+ case RR_Rotate_270:
+ extents->x2 = min(extents->x2 - xf86_crtc->x, h);
+ extents->y2 = min(extents->y2 - xf86_crtc->y, w);
+ break;
+ default:
+ extents->x2 = min(extents->x2 - xf86_crtc->x, w);
+ extents->y2 = min(extents->y2 - xf86_crtc->y, h);
+ }
return (extents->x1 < extents->x2 && extents->y1 < extents->y2);
}
@@ -353,7 +363,6 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
RegionPtr pRegion;
DrawablePtr pDraw;
ScreenPtr pScreen;
- GCPtr gc;
BoxRec extents;
RADEONInfoPtr info;
Bool force;
@@ -372,31 +381,87 @@ radeon_scanout_do_update(xf86CrtcPtr xf86_crtc, int scanout_id)
return FALSE;
pDraw = &drmmode_crtc->scanout[scanout_id].pixmap->drawable;
+ pScreen = pDraw->pScreen;
extents = *RegionExtents(pRegion);
RegionEmpty(pRegion);
- if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
- pDraw->width, pDraw->height))
+ if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width,
+ pDraw->height))
return FALSE;
- pScreen = pDraw->pScreen;
- gc = GetScratchGC(pDraw->depth, pScreen);
scrn = xf86_crtc->scrn;
info = RADEONPTR(scrn);
force = info->accel_state->force;
info->accel_state->force = TRUE;
- ValidateGC(pDraw, gc);
- (*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
- pDraw, gc,
- xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
- extents.x2 - extents.x1, extents.y2 - extents.y1,
- extents.x1, extents.y1);
- FreeScratchGC(gc);
+ if (xf86_crtc->driverIsPerformingTransform) {
+ SourceValidateProcPtr SourceValidate = pScreen->SourceValidate;
+ PictFormatPtr format = PictureWindowFormat(pScreen->root);
+ int error;
+ PicturePtr src, dst;
+ XID include_inferiors = IncludeInferiors;
+
+ src = CreatePicture(None,
+ &pScreen->root->drawable,
+ format,
+ CPSubwindowMode,
+ &include_inferiors, serverClient, &error);
+ if (!src) {
+ ErrorF("Failed to create source picture for transformed scanout "
+ "update\n");
+ goto out;
+ }
+
+ dst = CreatePicture(None, pDraw, format, 0L, NULL, serverClient, &error);
+ if (!dst) {
+ ErrorF("Failed to create destination picture for transformed scanout "
+ "update\n");
+ goto out;
+ }
- info->accel_state->force = force;
+ error = SetPictureTransform(src, &xf86_crtc->crtc_to_framebuffer);
+ if (error) {
+ ErrorF("SetPictureTransform failed for transformed scanout "
+ "update\n");
+ goto out;
+ }
+
+ if (xf86_crtc->filter)
+ SetPicturePictFilter(src, xf86_crtc->filter, xf86_crtc->params,
+ xf86_crtc->nparams);
+
+ extents.x1 += xf86_crtc->x - (xf86_crtc->filter_width >> 1);
+ extents.x2 += xf86_crtc->x + (xf86_crtc->filter_width >> 1);
+ extents.y1 += xf86_crtc->y - (xf86_crtc->filter_height >> 1);
+ extents.y2 += xf86_crtc->y + (xf86_crtc->filter_height >> 1);
+ pixman_f_transform_bounds(&xf86_crtc->f_framebuffer_to_crtc, &extents);
+
+ pScreen->SourceValidate = NULL;
+ CompositePicture(PictOpSrc,
+ src, NULL, dst,
+ extents.x1, extents.y1, 0, 0, extents.x1,
+ extents.y1, extents.x2 - extents.x1,
+ extents.y2 - extents.y1);
+ pScreen->SourceValidate = SourceValidate;
+
+ FreePicture(src, None);
+ FreePicture(dst, None);
+ } else {
+ GCPtr gc = GetScratchGC(pDraw->depth, pScreen);
+
+ ValidateGC(pDraw, gc);
+ (*gc->ops->CopyArea)(&pScreen->GetScreenPixmap(pScreen)->drawable,
+ pDraw, gc,
+ xf86_crtc->x + extents.x1, xf86_crtc->y + extents.y1,
+ extents.x2 - extents.x1, extents.y2 - extents.y1,
+ extents.x1, extents.y1);
+ FreeScratchGC(gc);
+ }
radeon_cs_flush_indirect(scrn);
+ out:
+ info->accel_state->force = force;
+
return TRUE;
}
@@ -445,8 +510,8 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
pDraw = &drmmode_crtc->scanout[0].pixmap->drawable;
extents = *RegionExtents(pRegion);
- if (!radeon_scanout_extents_intersect(&extents, xf86_crtc->x, xf86_crtc->y,
- pDraw->width, pDraw->height))
+ if (!radeon_scanout_extents_intersect(xf86_crtc, &extents, pDraw->width,
+ pDraw->height))
return;
scrn = xf86_crtc->scrn;
@@ -532,21 +597,19 @@ static void RADEONBlockHandler_KMS(BLOCKHANDLER_ARGS_DECL)
SCREEN_PTR(arg);
ScrnInfoPtr pScrn = xf86ScreenToScrn(pScreen);
RADEONInfoPtr info = RADEONPTR(pScrn);
+ xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
+ int c;
pScreen->BlockHandler = info->BlockHandler;
(*pScreen->BlockHandler) (BLOCKHANDLER_ARGS);
pScreen->BlockHandler = RADEONBlockHandler_KMS;
- if (info->tear_free || info->shadow_primary) {
- xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(pScrn);
- int c;
-
- for (c = 0; c < xf86_config->num_crtc; c++) {
- if (info->tear_free)
- radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]);
- else
- radeon_scanout_update(xf86_config->crtc[c]);
- }
+ for (c = 0; c < xf86_config->num_crtc; c++) {
+ if (info->tear_free)
+ radeon_scanout_flip(pScreen, info, xf86_config->crtc[c]);
+ else if (info->shadow_primary ||
+ xf86_config->crtc[c]->driverIsPerformingTransform)
+ radeon_scanout_update(xf86_config->crtc[c]);
}
radeon_cs_flush_indirect(pScrn);