From b99e8b022c4aaf586ae49e0eb597f0c34bc0e165 Mon Sep 17 00:00:00 2001 From: Chris Wilson Date: Thu, 18 Feb 2016 13:53:07 +0000 Subject: sna: Use dirtyfb for fallback direct rendering The preferred solution when direct rendering is too costly is to render into the backbuffer and flip. However, if the user insists, we need to tell the kernel when to flush the scanout due to direct rendering. Signed-off-by: Chris Wilson --- src/sna/kgem.c | 54 +++++++++++++++++++++++++++++++++++++++++++++++++++- src/sna/kgem.h | 3 +++ src/sna/sna_driver.c | 8 +++++--- 3 files changed, 61 insertions(+), 4 deletions(-) diff --git a/src/sna/kgem.c b/src/sna/kgem.c index aceedd46..abb9e029 100644 --- a/src/sna/kgem.c +++ b/src/sna/kgem.c @@ -86,6 +86,7 @@ search_snoop_cache(struct kgem *kgem, unsigned int num_pages, unsigned flags); #define DBG_NO_WC_MMAP 0 #define DBG_NO_BLT_Y 0 #define DBG_NO_SCANOUT_Y 0 +#define DBG_NO_DIRTYFB 0 #define DBG_NO_DETILING 0 #define DBG_DUMP 0 #define DBG_NO_MALLOC_CACHE 0 @@ -1499,6 +1500,47 @@ static bool test_can_scanout_y(struct kgem *kgem) return ret; } +static bool test_has_dirtyfb(struct kgem *kgem) +{ + struct drm_mode_fb_cmd create; + bool ret = false; + + if (DBG_NO_DIRTYFB) + return false; + + VG_CLEAR(create); + create.width = 32; + create.height = 32; + create.pitch = 4*32; + create.bpp = 32; + create.depth = 32; + create.handle = gem_create(kgem->fd, 1); + if (create.handle == 0) + return false; + + if (drmIoctl(kgem->fd, DRM_IOCTL_MODE_ADDFB, &create) == 0) { + struct drm_mode_fb_dirty_cmd dirty; + + memset(&dirty, 0, sizeof(dirty)); + dirty.fb_id = create.fb_id; + ret = drmIoctl(kgem->fd, + DRM_IOCTL_MODE_DIRTYFB, + &dirty) == 0; + + /* XXX There may be multiple levels of DIRTYFB, depending on + * whether the kernel thinks tracking dirty regions is + * beneficial vs flagging the whole fb as dirty. + */ + + drmIoctl(kgem->fd, + DRM_IOCTL_MODE_RMFB, + &create.fb_id); + } + gem_close(kgem->fd, create.handle); + + return ret; +} + static bool test_has_secure_batches(struct kgem *kgem) { if (DBG_NO_SECURE_BATCHES) @@ -1981,6 +2023,9 @@ void kgem_init(struct kgem *kgem, int fd, struct pci_device *dev, unsigned gen) DBG(("%s: can scanout Y-tiled surfaces? %d\n", __FUNCTION__, kgem->can_scanout_y)); + kgem->has_dirtyfb = test_has_dirtyfb(kgem); + DBG(("%s: has dirty fb? %d\n", __FUNCTION__, kgem->has_dirtyfb)); + kgem->has_secure_batches = test_has_secure_batches(kgem); DBG(("%s: can use privileged batchbuffers? %d\n", __FUNCTION__, kgem->has_secure_batches)); @@ -6090,7 +6135,7 @@ static void __kgem_flush(struct kgem *kgem, struct kgem_bo *bo) void kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo) { - if (!bo->needs_flush) + if (!bo->needs_flush && !bo->gtt_dirty) return; kgem_bo_submit(kgem, bo); @@ -6103,6 +6148,13 @@ void kgem_scanout_flush(struct kgem *kgem, struct kgem_bo *bo) if (bo->rq) __kgem_flush(kgem, bo); + if (bo->scanout && kgem->needs_dirtyfb) { + struct drm_mode_fb_dirty_cmd cmd; + memset(&cmd, 0, sizeof(cmd)); + cmd.fb_id = bo->delta; + (void)drmIoctl(kgem->fd, DRM_IOCTL_MODE_DIRTYFB, &cmd); + } + /* Whatever actually happens, we can regard the GTT write domain * as being flushed. */ diff --git a/src/sna/kgem.h b/src/sna/kgem.h index 6cf877cf..8bea755a 100644 --- a/src/sna/kgem.h +++ b/src/sna/kgem.h @@ -189,6 +189,7 @@ struct kgem { uint32_t has_no_reloc :1; uint32_t has_handle_lut :1; uint32_t has_wc_mmap :1; + uint32_t has_dirtyfb :1; uint32_t can_fence :1; uint32_t can_blt_cpu :1; @@ -196,6 +197,8 @@ struct kgem { uint32_t can_render_y :1; uint32_t can_scanout_y :1; + uint32_t needs_dirtyfb :1; + uint16_t fence_max; uint16_t half_cpu_cache_pages; uint32_t aperture_total, aperture_high, aperture_low, aperture_mappable, aperture_fenceable; diff --git a/src/sna/sna_driver.c b/src/sna/sna_driver.c index 14ec2f6a..b2455941 100644 --- a/src/sna/sna_driver.c +++ b/src/sna/sna_driver.c @@ -461,13 +461,13 @@ static bool enable_tear_free(struct sna *sna) return ENABLE_TEAR_FREE; } -static void setup_tear_free(struct sna *sna) +static bool setup_tear_free(struct sna *sna) { MessageType from; Bool enable; if (sna->flags & SNA_LINEAR_FB) - return; + return false; if ((sna->flags & SNA_HAS_FLIP) == 0) { from = X_PROBED; @@ -486,6 +486,7 @@ static void setup_tear_free(struct sna *sna) done: xf86DrvMsg(sna->scrn->scrnIndex, from, "TearFree %sabled\n", sna->flags & SNA_TEAR_FREE ? "en" : "dis"); + return sna->flags & SNA_TEAR_FREE; } /** @@ -653,7 +654,8 @@ static Bool sna_pre_init(ScrnInfoPtr scrn, int probe) } scrn->currentMode = scrn->modes; - setup_tear_free(sna); + if (!setup_tear_free(sna) && sna_mode_wants_tear_free(sna)) + sna->kgem.needs_dirtyfb = sna->kgem.has_dirtyfb; xf86SetGamma(scrn, zeros); xf86SetDpi(scrn, 0, 0); -- cgit v1.2.3