sna: Handle rotated slaved scanouts
authorChris Wilson <chris@chris-wilson.co.uk>
Thu, 17 Jul 2014 13:40:51 +0000 (14:40 +0100)
committerChris Wilson <chris@chris-wilson.co.uk>
Thu, 17 Jul 2014 14:20:05 +0000 (15:20 +0100)
As per the usual handling of rotated scanouts with unsupported
rotations, we stage the drawing onto a backbuffer then rotate onto the
crtc later. The difference here is that we must read the contents from
the master pixmap rather than our own screen pixmap.

Spotted was looking at slaved scanouts mistakenly setting the CRTC
transformed flag.

Reported-by: Tomas Pruzina <pruzinat@gmail.com>
Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=81383
Signed-off-by: Chris Wilson <chris@chris-wilson.co.uk>
src/sna/sna_display.c
src/sna/sna_driver.c

index 7c70b4c..584cb0d 100644 (file)
@@ -118,7 +118,8 @@ struct sna_crtc {
        xf86CrtcPtr base;
        struct drm_mode_modeinfo kmode;
        int dpms_mode;
-       PixmapPtr scanout_pixmap;
+       PixmapPtr slave_pixmap;
+       DamagePtr slave_damage;
        struct kgem_bo *bo, *shadow_bo;
        struct sna_cursor *cursor;
        uint32_t offset;
@@ -967,7 +968,7 @@ sna_crtc_apply(xf86CrtcPtr crtc)
        VG_CLEAR(arg);
        arg.crtc_id = sna_crtc->id;
        arg.fb_id = fb_id(sna_crtc->bo);
-       if (sna_crtc->transform) {
+       if (sna_crtc->transform || sna_crtc->slave_pixmap) {
                arg.x = 0;
                arg.y = 0;
                sna_crtc->offset = 0;
@@ -1309,6 +1310,21 @@ static void sna_mode_disable_shadow(struct sna *sna)
        sna->mode.shadow_dirty = false;
 }
 
+static void sna_crtc_slave_damage(DamagePtr damage, RegionPtr region, void *closure)
+{
+       struct sna_crtc *crtc = closure;
+       struct sna *sna = to_sna(crtc->base->scrn);
+       RegionPtr scr;
+
+       assert(crtc->slave_damage == damage);
+       assert(sna->mode.shadow_damage);
+
+       RegionTranslate(region, crtc->base->x, crtc->base->y);
+       scr = DamageRegion(sna->mode.shadow_damage);
+       RegionUnion(scr, scr, region);
+       RegionTranslate(region, -crtc->base->x, -crtc->base->y);
+}
+
 static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
 {
        if (crtc->shadow) {
@@ -1325,6 +1341,21 @@ static bool sna_crtc_enable_shadow(struct sna *sna, struct sna_crtc *crtc)
                assert(sna->mode.shadow == NULL);
        }
 
+       if (crtc->slave_pixmap) {
+               assert(crtc->slave_damage == NULL);
+
+               crtc->slave_damage = DamageCreate(sna_crtc_slave_damage, NULL,
+                                                 DamageReportRawRegion, TRUE,
+                                                 sna->scrn->pScreen, crtc);
+               if (crtc->slave_damage == NULL) {
+                       if (!--sna->mode.shadow_active)
+                               sna_mode_disable_shadow(sna);
+                       return false;
+               }
+
+               DamageRegister(&crtc->slave_pixmap->drawable, crtc->slave_damage);
+       }
+
        crtc->shadow = true;
        sna->mode.shadow_active++;
        return true;
@@ -1339,8 +1370,12 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
        DBG(("%s: disabling for crtc %d\n", __FUNCTION__, crtc->id));
        assert(sna->mode.shadow_active > 0);
 
-       if (!--sna->mode.shadow_active)
-               sna_mode_disable_shadow(sna);
+       if (crtc->slave_damage) {
+               assert(crtc->slave_pixmap);
+               DamageUnregister(&crtc->slave_scanout->drawable, crtc->slave_damage);
+               DamageDestroy(crtc->slave_damage);
+               crtc->slave_damage = NULL;
+       }
 
        if (crtc->shadow_bo) {
                if (!crtc->transform) {
@@ -1361,6 +1396,9 @@ static void sna_crtc_disable_shadow(struct sna *sna, struct sna_crtc *crtc)
                crtc->shadow_bo = NULL;
        }
 
+       if (!--sna->mode.shadow_active)
+               sna_mode_disable_shadow(sna);
+
        crtc->shadow = false;
 }
 
@@ -1703,21 +1741,7 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
        sna_crtc->transform = false;
        sna_crtc->rotation = RR_Rotate_0;
 
-       if (sna_crtc->scanout_pixmap) {
-               DBG(("%s: attaching to scanout pixmap\n", __FUNCTION__));
-
-               bo = sna_pixmap_pin(sna_crtc->scanout_pixmap, PIN_SCANOUT);
-               if (bo == NULL)
-                       return NULL;
-
-               if (!get_fb(sna, bo,
-                           sna_crtc->scanout_pixmap->drawable.width,
-                           sna_crtc->scanout_pixmap->drawable.height))
-                       return NULL;
-
-               sna_crtc->transform = true;
-               return kgem_bo_reference(bo);
-       } else if (use_shadow(sna, crtc)) {
+       if (use_shadow(sna, crtc)) {
                unsigned long tiled_limit;
                int tiling;
 
@@ -1756,17 +1780,29 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
                sna_crtc->transform = true;
                return bo;
        } else {
-               unsigned rotation;
+               if (sna_crtc->slave_pixmap) {
+                       DBG(("%s: attaching to scanout pixmap\n", __FUNCTION__));
+                       bo = sna_pixmap_pin(sna_crtc->slave_pixmap, PIN_SCANOUT);
+                       if (bo == NULL)
+                               return NULL;
 
-               DBG(("%s: attaching to framebuffer\n", __FUNCTION__));
-               bo = sna_pixmap_pin(sna->front, PIN_SCANOUT);
-               if (bo == NULL)
-                       return NULL;
+                       if (!get_fb(sna, bo,
+                                   sna_crtc->slave_pixmap->drawable.width,
+                                   sna_crtc->slave_pixmap->drawable.height))
+                               return NULL;
+               } else {
+                       DBG(("%s: attaching to framebuffer\n", __FUNCTION__));
+                       bo = sna_pixmap_pin(sna->front, PIN_SCANOUT);
+                       if (bo == NULL)
+                               return NULL;
 
-               if (!get_fb(sna, bo, scrn->virtualX, scrn->virtualY))
-                       return NULL;
+                       if (!get_fb(sna, bo, scrn->virtualX, scrn->virtualY))
+                               return NULL;
+               }
 
                if (sna->flags & SNA_TEAR_FREE) {
+                       assert(sna_crtc->slave_pixmap == NULL);
+
                        DBG(("%s: enabling TearFree shadow\n", __FUNCTION__));
                        if (!sna_crtc_enable_shadow(sna, sna_crtc))
                                return NULL;
@@ -1805,9 +1841,8 @@ static struct kgem_bo *sna_crtc_attach(xf86CrtcPtr crtc)
                } else
                        sna_crtc_disable_shadow(sna, sna_crtc);
 
-               rotation = rotation_reduce(&sna_crtc->primary, crtc->rotation);
-               assert(sna_crtc->primary.rotation.supported & rotation);
-               sna_crtc->rotation = rotation;
+               sna_crtc->rotation = rotation_reduce(&sna_crtc->primary, crtc->rotation);
+               assert(sna_crtc->primary.rotation.supported & sna_crtc->rotation);
                return kgem_bo_reference(bo);
        }
 }
@@ -2127,11 +2162,19 @@ sna_crtc_destroy(xf86CrtcPtr crtc)
 static Bool
 sna_crtc_set_scanout_pixmap(xf86CrtcPtr crtc, PixmapPtr pixmap)
 {
-       assert(to_sna_crtc(crtc));
+       struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
+
+       if (sna_crtc == NULL)
+               return FALSE;
+
        DBG(("%s: CRTC:%d, pipe=%d setting scanout pixmap=%ld\n",
-            __FUNCTION__,to_sna_crtc(crtc)->id, to_sna_crtc(crtc)->pipe,
+            __FUNCTION__, sna_crtc->id,  sna_crtc->pipe,
             pixmap ? pixmap->drawable.serialNumber : 0));
-       to_sna_crtc(crtc)->scanout_pixmap = pixmap;
+
+       sna_crtc->slave_pixmap = pixmap;
+       if (pixmap == NULL)
+               sna_crtc_disable(crtc);
+
        return TRUE;
 }
 #endif
@@ -6053,11 +6096,26 @@ static void transformed_box(BoxRec *box, xf86CrtcPtr crtc)
                box->y2 = crtc->mode.VDisplay;
 }
 
+inline static DrawablePtr crtc_source(xf86CrtcPtr crtc, int16_t *sx, int16_t *sy)
+{
+       struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
+       if (sna_crtc->slave_pixmap) {
+               *sx = -crtc->x;
+               *sy = -crtc->y;
+               return &sna_crtc->slave_pixmap->drawable;
+       } else {
+               *sx = *sy = 0;
+               return &to_sna(crtc->scrn)->front->drawable;
+       }
+}
+
 static void
 sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
 {
+       int16_t sx, sy;
        struct sna *sna = to_sna(crtc->scrn);
        ScreenPtr screen = sna->scrn->pScreen;
+       DrawablePtr draw = crtc_source(crtc, &sx, &sy);
        PictFormatPtr format;
        PicturePtr src, dst;
        PixmapPtr pixmap;
@@ -6066,7 +6124,7 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
 
        DBG(("%s: compositing transformed damage boxes\n", __FUNCTION__));
 
-       error = sna_render_format_for_depth(sna->front->drawable.depth);
+       error = sna_render_format_for_depth(draw->depth);
        depth = PIXMAN_FORMAT_DEPTH(error);
        format = PictureMatchFormat(screen, depth, error);
        if (format == NULL) {
@@ -6085,11 +6143,11 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
 
        if (!screen->ModifyPixmapHeader(pixmap,
                                        crtc->mode.HDisplay, crtc->mode.VDisplay,
-                                       depth, sna->front->drawable.bitsPerPixel,
+                                       depth, draw->bitsPerPixel,
                                        bo->pitch, ptr))
                goto free_pixmap;
 
-       src = CreatePicture(None, &sna->front->drawable, format,
+       src = CreatePicture(None, draw, format,
                            0, NULL, serverClient, &error);
        if (!src)
                goto free_pixmap;
@@ -6124,7 +6182,7 @@ sna_crtc_redisplay__fallback(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
                             box.x1, box.y1, box.x2, box.y2));
 
                        fbComposite(PictOpSrc, src, NULL, dst,
-                                   box.x1, box.y1,
+                                   box.x1 + sx, box.y1 + sy,
                                    0, 0,
                                    box.x1, box.y1,
                                    box.x2 - box.x1, box.y2 - box.y1);
@@ -6142,8 +6200,10 @@ free_pixmap:
 static void
 sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo *bo)
 {
+       int16_t sx, sy;
        struct sna *sna = to_sna(crtc->scrn);
        ScreenPtr screen = crtc->scrn->pScreen;
+       DrawablePtr draw = crtc_source(crtc, &sx, &sy);
        struct sna_composite_op tmp;
        PictFormatPtr format;
        PicturePtr src, dst;
@@ -6153,7 +6213,7 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
 
        DBG(("%s: compositing transformed damage boxes\n", __FUNCTION__));
 
-       error = sna_render_format_for_depth(sna->front->drawable.depth);
+       error = sna_render_format_for_depth(draw->depth);
        depth = PIXMAN_FORMAT_DEPTH(error);
        format = PictureMatchFormat(screen, depth, error);
        if (format == NULL) {
@@ -6168,7 +6228,7 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
 
        if (!screen->ModifyPixmapHeader(pixmap,
                                        crtc->mode.HDisplay, crtc->mode.VDisplay,
-                                       depth, sna->front->drawable.bitsPerPixel,
+                                       depth, draw->bitsPerPixel,
                                        bo->pitch, NULL))
                goto free_pixmap;
 
@@ -6177,7 +6237,7 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
                goto free_pixmap;
        }
 
-       src = CreatePicture(None, &sna->front->drawable, format,
+       src = CreatePicture(None, draw, format,
                            0, NULL, serverClient, &error);
        if (!src)
                goto free_pixmap;
@@ -6200,7 +6260,7 @@ sna_crtc_redisplay__composite(xf86CrtcPtr crtc, RegionPtr region, struct kgem_bo
 
        if (!sna->render.composite(sna,
                                   PictOpSrc, src, NULL, dst,
-                                  0, 0,
+                                  sx, sy,
                                   0, 0,
                                   0, 0,
                                   crtc->mode.HDisplay, crtc->mode.VDisplay,
@@ -6238,10 +6298,11 @@ free_pixmap:
 static void
 sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region)
 {
+       int16_t tx, ty, sx, sy;
        struct sna *sna = to_sna(crtc->scrn);
        struct sna_crtc *sna_crtc = to_sna_crtc(crtc);
-       struct sna_pixmap *priv = sna_pixmap(sna->front);
-       int16_t tx, ty;
+       DrawablePtr draw = crtc_source(crtc, &sx, &sy);
+       struct sna_pixmap *priv = sna_pixmap((PixmapPtr)draw);
 
        assert(sna_crtc);
        DBG(("%s: crtc %d [pipe=%d], damage (%d, %d), (%d, %d) x %d\n",
@@ -6257,7 +6318,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region)
 
                RegionTranslate(region, -crtc->bounds.x1, -crtc->bounds.y1);
                sna_blt_fill_boxes(sna, GXcopy,
-                                  sna_crtc->bo, sna->front->drawable.bitsPerPixel,
+                                  sna_crtc->bo, draw->bitsPerPixel,
                                   priv->clear_color,
                                   region_rects(region), region_num_rects(region));
                return;
@@ -6276,7 +6337,7 @@ sna_crtc_redisplay(xf86CrtcPtr crtc, RegionPtr region)
                tmp.bitsPerPixel = sna->front->drawable.bitsPerPixel;
 
                if (sna->render.copy_boxes(sna, GXcopy,
-                                          &sna->front->drawable, priv->gpu_bo, 0, 0,
+                                          draw, priv->gpu_bo, sx, sy,
                                           &tmp, sna_crtc->bo, -tx, -ty,
                                           region_rects(region), region_num_rects(region), 0))
                        return;
@@ -6403,6 +6464,9 @@ void sna_mode_redisplay(struct sna *sna)
                        if (RegionNotEmpty(&damage))
                                sna_crtc_redisplay__fallback(crtc, &damage, sna_crtc->bo);
                        RegionUninit(&damage);
+
+                       if (sna_crtc->slave_damage)
+                               DamageEmpty(sna_crtc->slave_damage);
                }
 
                RegionEmpty(region);
@@ -6530,6 +6594,9 @@ disable1:
                        }
                }
                RegionUninit(&damage);
+
+               if (sna_crtc->slave_damage)
+                       DamageEmpty(sna_crtc->slave_damage);
        }
 
        if (sna->mode.shadow) {
index 4454b32..2eac852 100644 (file)
@@ -487,6 +487,11 @@ static void setup_dri(struct sna *sna)
 
 static bool enable_tear_free(struct sna *sna)
 {
+#if HAS_PIXMAP_SHARING
+       if (sna->scrn->is_gpu)
+               return false;
+#endif
+
        /* Under certain conditions, we should enable TearFree by default,
         * for example when the hardware requires pageflipping to run within
         * its power/performance budget.