From: Michel Dänzer <michel.daenzer@xxxxxxx> This reduces PCIe bandwidth usage and tearing. Signed-off-by: Michel Dänzer <michel.daenzer at 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