From: Michel Dänzer <michel.daen...@amd.com>

This reduces PCIe bandwidth usage and tearing.

Signed-off-by: Michel Dänzer <michel.daen...@amd.com>
---
 src/radeon_kms.c | 94 +++++++++++++++++++++++++++++++++++++++++++++++++++++---
 1 file changed, 90 insertions(+), 4 deletions(-)

diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index d48c9b6..adf56fd 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -383,9 +383,9 @@ static Bool RADEONCreateScreenResources_KMS(ScreenPtr 
pScreen)
 
 #ifdef RADEON_PIXMAP_SHARING
 static void
-redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr dirty)
+redisplay_dirty(PixmapDirtyUpdatePtr dirty)
 {
-       ScrnInfoPtr pScrn = xf86ScreenToScrn(screen);
+       ScrnInfoPtr pScrn = xf86ScreenToScrn(dirty->src->drawable.pScreen);
        RegionRec pixregion;
 
        PixmapRegionInit(&pixregion, dirty->slave_dst);
@@ -399,6 +399,90 @@ redisplay_dirty(ScreenPtr screen, PixmapDirtyUpdatePtr 
dirty)
        radeon_cs_flush_indirect(pScrn);
        DamageRegionProcessPending(&dirty->slave_dst->drawable);
        RegionUninit(&pixregion);
+
+       DamageEmpty(dirty->damage);
+}
+
+static void
+radeon_prime_scanout_update_abort(xf86CrtcPtr crtc, void *event_data)
+{
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+    drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+void
+radeon_prime_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t 
usec,
+                                   void *event_data)
+{
+    ScrnInfoPtr scrn = crtc->scrn;
+    ScreenPtr screen = scrn->pScreen;
+    drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+    PixmapPtr scanoutpix = crtc->randr_crtc->scanout_pixmap;
+    PixmapDirtyUpdatePtr dirty;
+
+    xorg_list_for_each_entry(dirty, &screen->pixmap_dirty_list, ent) {
+       if (dirty->src == scanoutpix &&
+           dirty->slave_dst == drmmode_crtc->scanout[0].pixmap) {
+           redisplay_dirty(dirty);
+           break;
+       }
+    }
+
+    drmmode_crtc->scanout_update_pending = FALSE;
+}
+
+static void
+radeon_prime_scanout_update(PixmapDirtyUpdatePtr dirty)
+{
+    ScreenPtr screen = dirty->slave_dst->drawable.pScreen;
+    ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+    xf86CrtcConfigPtr xf86_config = XF86_CRTC_CONFIG_PTR(scrn);
+    xf86CrtcPtr xf86_crtc = NULL;
+    drmmode_crtc_private_ptr drmmode_crtc = NULL;
+    uintptr_t drm_queue_seq;
+    drmVBlank vbl;
+    int c;
+
+    /* Find the CRTC which is scanning out from this slave pixmap */
+    for (c = 0; c < xf86_config->num_crtc; c++) {
+       xf86_crtc = xf86_config->crtc[c];
+       drmmode_crtc = xf86_crtc->driver_private;
+       if (drmmode_crtc->scanout[0].pixmap == dirty->slave_dst)
+           break;
+    }
+
+    if (c == xf86_config->num_crtc ||
+       !xf86_crtc->enabled ||
+       drmmode_crtc->scanout_update_pending ||
+       !drmmode_crtc->scanout[0].pixmap ||
+       drmmode_crtc->pending_dpms_mode != DPMSModeOn)
+       return;
+
+    drm_queue_seq = radeon_drm_queue_alloc(xf86_crtc,
+                                          RADEON_DRM_QUEUE_CLIENT_DEFAULT,
+                                          RADEON_DRM_QUEUE_ID_DEFAULT, NULL,
+                                          radeon_prime_scanout_update_handler,
+                                          radeon_prime_scanout_update_abort);
+    if (drm_queue_seq == RADEON_DRM_QUEUE_ERROR) {
+       xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+                  "radeon_drm_queue_alloc failed for PRIME update\n");
+       return;
+    }
+
+    vbl.request.type = DRM_VBLANK_RELATIVE | DRM_VBLANK_EVENT;
+    vbl.request.type |= radeon_populate_vbl_request_type(xf86_crtc);
+    vbl.request.sequence = 1;
+    vbl.request.signal = drm_queue_seq;
+    if (drmWaitVBlank(RADEONPTR(scrn)->dri2.drm_fd, &vbl)) {
+       xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+                  "drmWaitVBlank failed for PRIME update: %s\n",
+                  strerror(errno));
+       radeon_drm_abort_entry(drm_queue_seq);
+       return;
+    }
+
+    drmmode_crtc->scanout_update_pending = TRUE;
 }
 
 static void
@@ -413,8 +497,10 @@ radeon_dirty_update(ScreenPtr screen)
        xorg_list_for_each_entry(ent, &screen->pixmap_dirty_list, ent) {
                region = DamageRegion(ent->damage);
                if (RegionNotEmpty(region)) {
-                       redisplay_dirty(screen, ent);
-                       DamageEmpty(ent->damage);
+                       if (screen->isGPU)
+                               radeon_prime_scanout_update(ent);
+                       else
+                               redisplay_dirty(ent);
                }
        }
 }
-- 
2.9.3

_______________________________________________
amd-gfx mailing list
amd-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/amd-gfx

Reply via email to