From a45b2ea11c15f35c36330ff27cb45854a29c2e2c Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 17 Jul 2014 14:40:51 +0100 Subject: [PATCH] sna: Handle rotated slaved scanouts 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 Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=81383 Signed-off-by: Chris Wilson --- src/sna/sna_display.c | 155 ++++++++++++++++++++++++++++++++++++-------------- src/sna/sna_driver.c | 5 ++ 2 files changed, 116 insertions(+), 44 deletions(-) diff --git a/src/sna/sna_display.c b/src/sna/sna_display.c index 7c70b4c..584cb0d 100644 --- a/src/sna/sna_display.c +++ b/src/sna/sna_display.c @@ -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) { diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 4454b32..2eac852 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -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. -- 2.7.4