Commit 64ae01ea authored by Simo Melenius's avatar Simo Melenius
Browse files

randr: apply transforms in reverse PRIME shared pixmap updates

For reverse PRIME heads, scaling was broken as the compositing of the
shared pixmaps wasn't properly configured to take into account scaling
(and other transformations). For example, by scaling a reverse PRIME
head by 2x2 the user would only see the top-left quadrant of the 2x2
screenspace instead of the full screenspace scaled down to the size of
the shared pixmap.

This change brings the RandR transformation available for tracking and
updating of dirty regions, and subsequently the CompositeRotate()
function which renders the transformation onto the shared pixmap. For
transforms with simple translations only a separate execution path is
tracked so that direct copying can be used.

These changes should fix scaling, and to some extent, arbitrary
transformations, for all heads that are reverse PRIME sinks.

Note that they only clean up certain parts of the viewport
transformation and composition pipeline. A more thorough overhaul of
how all the offsets and transformations are managed would be in order
to make all combinations of randr screen configurations work
seamlessly. I tried to be careful not to break existing functionality
but there are things that were broken in the first place and remain to
be so.

As a quick test, basic scaling like this should now work properly with
reverse PRIME outputs:

  xrandr --output <X> --scale 0.5x0.5
  xrandr --output <X> --scale 2x2

Arbitrary transforms still exhibit various quirks and artifacts but
something like a basic free rotation should now behave a bit better
than before with reverse PRIME outputs:

  xrandr --output <X> --transform 0.707,-0.707,0,0.707,0.707,0,0,0,1
parent 1626e9fa
Pipeline #217497 passed with stages
in 7 minutes and 39 seconds
......@@ -41,6 +41,7 @@ from The Open Group.
#include "gcstruct.h"
#include "servermd.h"
#include "X11/extensions/render.h"
#include "pixmapstr.h"
#include "picturestr.h"
#include "randrstr.h"
......@@ -184,6 +185,7 @@ Bool
PixmapStartDirtyTracking(DrawablePtr src,
PixmapPtr secondary_dst,
int x, int y, int dst_x, int dst_y,
RRTransformPtr rr_transform,
Rotation rotation)
ScreenPtr screen = src->pScreen;
......@@ -192,6 +194,9 @@ PixmapStartDirtyTracking(DrawablePtr src,
RegionRec dstregion;
BoxRec box;
if (rr_transform && pixman_transform_is_identity(&rr_transform->transform))
rr_transform = NULL;
dirty_update = calloc(1, sizeof(PixmapDirtyUpdateRec));
if (!dirty_update)
return FALSE;
......@@ -203,20 +208,30 @@ PixmapStartDirtyTracking(DrawablePtr src,
dirty_update->dst_x = dst_x;
dirty_update->dst_y = dst_y;
dirty_update->rotation = rotation;
dirty_update->transform_is_simple = TRUE;
dirty_update->damage = DamageCreate(NULL, PixmapDirtyDamageDestroy,
DamageReportNone, TRUE, screen,
if (rotation != RR_Rotate_0) {
RRTransformCompute(x, y,
/* Compute complex transforms if rotation or a custom transform applies.
* Otherwise initialize transforms to a simple translation. */
if (rotation != RR_Rotate_0 || rr_transform) {
if (RRTransformCompute(x, y,
&dirty_update->f_inverse)) {
dirty_update->transform_is_simple = FALSE;
} else {
pixman_transform_init_translate(&dirty_update->transform, IntToxFixed(x), IntToxFixed(y));
pixman_f_transform_init_translate(&dirty_update->f_transform, x, y);
pixman_f_transform_init_translate(&dirty_update->f_inverse, -x, -y);
if (!dirty_update->damage) {
return FALSE;
......@@ -336,10 +351,6 @@ PixmapDirtyCompositeRotate(PixmapPtr dst_pixmap,
BoxRec dst_box;
dst_box = *b;
dst_box.x1 += dirty->x;
dst_box.x2 += dirty->x;
dst_box.y1 += dirty->y;
dst_box.y2 += dirty->y;
pixman_f_transform_bounds(&dirty->f_inverse, &dst_box);
......@@ -386,6 +397,10 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
box.x2 = dst->drawable.width;
box.y2 = dst->drawable.height;
/* Bring box to the same coordinate space as the damage region (i.e. the
* master framebuffer). */
pixman_f_transform_bounds(&dirty->f_transform, &box);
RegionInit(&pixregion, &box, 1);
......@@ -397,7 +412,6 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
SourceValidate = pScreen->SourceValidate;
pScreen->SourceValidate = miSourceValidate;
RegionTranslate(&pixregion, dirty->x, dirty->y);
RegionIntersect(&pixregion, &pixregion, region);
if (RegionNil(&pixregion)) {
......@@ -405,12 +419,17 @@ Bool PixmapSyncDirtyHelper(PixmapDirtyUpdatePtr dirty)
return FALSE;
RegionTranslate(&pixregion, -dirty->x, -dirty->y);
if (!pScreen->root || dirty->rotation == RR_Rotate_0)
if ((!pScreen->root || dirty->rotation == RR_Rotate_0) && dirty->transform_is_simple) {
/* For plain area copy shift pixregion to the right position manually. */
PixmapDirtyCopyArea(dst, dirty, &pixregion);
} else {
/* No translation needed, CompositeRotate will use the transform matrix
* implicitly in rendering. */
PixmapDirtyCompositeRotate(dst, dirty, &pixregion);
pScreen->SourceValidate = SourceValidate;
return TRUE;
......@@ -1445,12 +1445,16 @@ msStartFlippingPixmapTracking(RRCrtcPtr crtc, DrawablePtr src,
ppriv2 = msGetPixmapPriv(&ms->drmmode, secondary_dst2->primary_pixmap);
if (!PixmapStartDirtyTracking(src, secondary_dst1, x, y,
dst_x, dst_y, rotation)) {
dst_x, dst_y,
rotation)) {
return FALSE;
if (!PixmapStartDirtyTracking(src, secondary_dst2, x, y,
dst_x, dst_y, rotation)) {
dst_x, dst_y,
rotation)) {
PixmapStopDirtyTracking(src, secondary_dst1);
return FALSE;
......@@ -1688,6 +1688,7 @@ drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(crtc->scrn);
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
drmmode_ptr drmmode = drmmode_crtc->drmmode;
RRCrtcPtr rr_crtc;
int c, total_width = 0, max_height = 0, this_x = 0;
if (*target) {
......@@ -1731,7 +1732,9 @@ drmmode_set_target_scanout_pixmap_gpu(xf86CrtcPtr crtc, PixmapPtr ppix,
screen->height = screenpix->drawable.height = max_height;
drmmode_crtc->prime_pixmap_x = this_x;
rr_crtc = crtc->randr_crtc;
PixmapStartDirtyTracking(&ppix->drawable, screenpix, 0, 0, this_x, 0,
rr_crtc ? &rr_crtc->client_pending_transform : NULL,
*target = ppix;
return TRUE;
......@@ -71,6 +71,8 @@ SOFTWARE.
#define NullPixmap ((PixmapPtr)0)
typedef struct _rrTransform *RRTransformPtr;
typedef struct _Drawable *DrawablePtr;
typedef struct _Pixmap *PixmapPtr;
......@@ -124,6 +126,7 @@ extern _X_EXPORT Bool
PixmapStartDirtyTracking(DrawablePtr src,
PixmapPtr slave_dst,
int x, int y, int dst_x, int dst_y,
RRTransformPtr rr_transform,
Rotation rotation);
extern _X_EXPORT Bool
......@@ -95,6 +95,7 @@ typedef struct _PixmapDirtyUpdate {
struct xorg_list ent;
int dst_x, dst_y;
Rotation rotation;
Bool transform_is_simple;
PictTransform transform;
struct pixman_f_transform f_transform, f_inverse;
} PixmapDirtyUpdateRec;
......@@ -380,6 +380,7 @@ typedef void (*SyncSharedPixmapProcPtr)(PixmapDirtyUpdatePtr);
typedef Bool (*StartPixmapTrackingProcPtr)(DrawablePtr, PixmapPtr,
int x, int y,
int dst_x, int dst_y,
RRTransformPtr rr_transform,
Rotation rotation);
typedef Bool (*PresentSharedPixmapProcPtr)(PixmapPtr);
......@@ -600,7 +600,9 @@ fail: /* If flipping funcs fail, just fall back to unsynchronized */
crtc->scanout_pixmap = spix_front;
primary->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0, rotation);
primary->StartPixmapTracking(mrootdraw, spix_front, x, y, 0, 0,
return TRUE;
Supports Markdown
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment