From: Michel Dänzer <michel.daenzer@xxxxxxx> (Ported from radeon commits 1106b2f773ad0611c729b27f4c192a26b43ef1e7 and 5fea5ef2f07eee4a0f94baab427010b936f1d4b4) v2: * Squash in radeon fix for TearFree regression * Remove preprocessor guards for compatibility with libdrm < 2.4.72 (Emil Velikov) Signed-off-by: Michel Dänzer <michel.daenzer at amd.com> --- src/amdgpu_dri2.c | 3 +- src/amdgpu_kms.c | 18 +++++------ src/amdgpu_present.c | 5 +-- src/amdgpu_probe.h | 1 + src/drmmode_display.c | 89 ++++++++++++++++++++++++++++++++++++++++++++------- src/drmmode_display.h | 13 +++++++- 6 files changed, 104 insertions(+), 25 deletions(-) diff --git a/src/amdgpu_dri2.c b/src/amdgpu_dri2.c index 31ac3f3..c3a112d 100644 --- a/src/amdgpu_dri2.c +++ b/src/amdgpu_dri2.c @@ -563,7 +563,8 @@ amdgpu_dri2_schedule_flip(xf86CrtcPtr crtc, ClientPtr client, AMDGPU_DRM_QUEUE_ID_DEFAULT, flip_info, ref_crtc_hw_id, amdgpu_dri2_flip_event_handler, - amdgpu_dri2_flip_event_abort, FLIP_VSYNC)) { + amdgpu_dri2_flip_event_abort, FLIP_VSYNC, + target_msc - amdgpu_get_msc_delta(draw, crtc))) { info->drmmode.dri2_flipping = TRUE; return TRUE; } diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c index 319b572..cadd928 100644 --- a/src/amdgpu_kms.c +++ b/src/amdgpu_kms.c @@ -701,9 +701,9 @@ amdgpu_prime_scanout_flip(PixmapDirtyUpdatePtr ent) return; } - if (drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, - drmmode_crtc->scanout[scanout_id].fb_id, - DRM_MODE_PAGE_FLIP_EVENT, (void*)drm_queue_seq)) { + if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc, + drmmode_crtc->scanout[scanout_id].fb_id, + 0, drm_queue_seq, 0) != 0) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n", __func__, strerror(errno)); return; @@ -949,8 +949,8 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info, xf86CrtcPtr xf86_crtc) { drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private; - ScrnInfoPtr scrn; - AMDGPUEntPtr pAMDGPUEnt; + ScrnInfoPtr scrn = xf86_crtc->scrn; + AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); uintptr_t drm_queue_seq; unsigned scanout_id; @@ -961,7 +961,6 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info, if (!amdgpu_scanout_do_update(xf86_crtc, scanout_id)) return; - scrn = xf86_crtc->scrn; drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, AMDGPU_DRM_QUEUE_ID_DEFAULT, @@ -973,10 +972,9 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info, return; } - pAMDGPUEnt = AMDGPUEntPriv(scrn); - if (drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, - drmmode_crtc->scanout[scanout_id].fb_id, - DRM_MODE_PAGE_FLIP_EVENT, (void*)drm_queue_seq)) { + if (drmmode_page_flip_target_relative(pAMDGPUEnt, drmmode_crtc, + drmmode_crtc->scanout[scanout_id].fb_id, + 0, drm_queue_seq, 0) != 0) { xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed in %s: %s\n", __func__, strerror(errno)); return; diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c index dcb18da..3646190 100644 --- a/src/amdgpu_present.c +++ b/src/amdgpu_present.c @@ -329,7 +329,8 @@ amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc, pixmap, event_id, event, crtc_id, amdgpu_present_flip_event, amdgpu_present_flip_abort, - sync_flip ? FLIP_VSYNC : FLIP_ASYNC); + sync_flip ? FLIP_VSYNC : FLIP_ASYNC, + target_msc); if (!ret) xf86DrvMsg(scrn->scrnIndex, X_ERROR, "present flip failed\n"); else @@ -366,7 +367,7 @@ amdgpu_present_unflip(ScreenPtr screen, uint64_t event_id) if (amdgpu_do_pageflip(scrn, AMDGPU_DRM_QUEUE_CLIENT_DEFAULT, pixmap, event_id, event, -1, amdgpu_present_flip_event, - amdgpu_present_flip_abort, FLIP_VSYNC)) + amdgpu_present_flip_abort, FLIP_VSYNC, 0)) return; modeset: diff --git a/src/amdgpu_probe.h b/src/amdgpu_probe.h index 1ec1299..0302d02 100644 --- a/src/amdgpu_probe.h +++ b/src/amdgpu_probe.h @@ -56,6 +56,7 @@ extern DriverRec AMDGPU; typedef struct { Bool HasCRTC2; /* All cards except original Radeon */ + Bool has_page_flip_target; amdgpu_device_handle pDev; diff --git a/src/drmmode_display.c b/src/drmmode_display.c index a75cc5c..8cedc5f 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -2132,6 +2132,59 @@ static void drm_wakeup_handler(pointer data, int err, pointer p) } #endif +static Bool drmmode_probe_page_flip_target(AMDGPUEntPtr pAMDGPUEnt) +{ + uint64_t cap_value; + + return drmGetCap(pAMDGPUEnt->fd, DRM_CAP_PAGE_FLIP_TARGET, + &cap_value) == 0 && cap_value != 0; +} + +static int +drmmode_page_flip(AMDGPUEntPtr pAMDGPUEnt, drmmode_crtc_private_ptr drmmode_crtc, + int fb_id, uint32_t flags, uintptr_t drm_queue_seq) +{ + flags |= DRM_MODE_PAGE_FLIP_EVENT; + return drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, + fb_id, flags, (void*)drm_queue_seq); +} + +int +drmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, + drmmode_crtc_private_ptr drmmode_crtc, + int fb_id, uint32_t flags, + uintptr_t drm_queue_seq, uint32_t target_msc) +{ + if (pAMDGPUEnt->has_page_flip_target) { + flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_ABSOLUTE; + return drmModePageFlipTarget(pAMDGPUEnt->fd, + drmmode_crtc->mode_crtc->crtc_id, + fb_id, flags, (void*)drm_queue_seq, + target_msc); + } + + return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, + drm_queue_seq); +} + +int +drmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, + drmmode_crtc_private_ptr drmmode_crtc, + int fb_id, uint32_t flags, + uintptr_t drm_queue_seq, uint32_t target_msc) +{ + if (pAMDGPUEnt->has_page_flip_target) { + flags |= DRM_MODE_PAGE_FLIP_EVENT | DRM_MODE_PAGE_FLIP_TARGET_RELATIVE; + return drmModePageFlipTarget(pAMDGPUEnt->fd, + drmmode_crtc->mode_crtc->crtc_id, + fb_id, flags, (void*)drm_queue_seq, + target_msc); + } + + return drmmode_page_flip(pAMDGPUEnt, drmmode_crtc, fb_id, flags, + drm_queue_seq); +} + Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) { AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(pScrn); @@ -2198,6 +2251,8 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp) drmmode->event_context.vblank_handler = amdgpu_drm_queue_handler; drmmode->event_context.page_flip_handler = amdgpu_drm_queue_handler; + pAMDGPUEnt->has_page_flip_target = drmmode_probe_page_flip_target(pAMDGPUEnt); + drmModeFreeResources(mode_res); return TRUE; } @@ -2535,7 +2590,8 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, PixmapPtr new_front, uint64_t id, void *data, int ref_crtc_hw_id, amdgpu_drm_handler_proc handler, amdgpu_drm_abort_proc abort, - enum drmmode_flip_sync flip_sync) + enum drmmode_flip_sync flip_sync, + uint32_t target_msc) { AMDGPUEntPtr pAMDGPUEnt = AMDGPUEntPriv(scrn); xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn); @@ -2543,7 +2599,7 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; int i; - uint32_t flip_flags = DRM_MODE_PAGE_FLIP_EVENT; + uint32_t flip_flags = flip_sync == FLIP_ASYNC ? DRM_MODE_PAGE_FLIP_ASYNC : 0; drmmode_flipdata_ptr flipdata; uintptr_t drm_queue_seq = 0; uint32_t new_front_handle; @@ -2585,9 +2641,6 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, flipdata->handler = handler; flipdata->abort = abort; - if (flip_sync == FLIP_ASYNC) - flip_flags |= DRM_MODE_PAGE_FLIP_ASYNC; - for (i = 0; i < config->num_crtc; i++) { crtc = config->crtc[i]; @@ -2613,13 +2666,23 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, goto error; } - if (drmModePageFlip(pAMDGPUEnt->fd, drmmode_crtc->mode_crtc->crtc_id, - drmmode->fb_id, flip_flags, - (void*)drm_queue_seq)) { - xf86DrvMsg(scrn->scrnIndex, X_WARNING, - "flip queue failed: %s\n", strerror(errno)); - goto error; + if (drmmode_crtc->hw_id == ref_crtc_hw_id) { + if (drmmode_page_flip_target_absolute(pAMDGPUEnt, + drmmode_crtc, + drmmode->fb_id, + flip_flags, + drm_queue_seq, + target_msc) != 0) + goto flip_error; + } else { + if (drmmode_page_flip_target_relative(pAMDGPUEnt, + drmmode_crtc, + drmmode->fb_id, + flip_flags, + drm_queue_seq, 0) != 0) + goto flip_error; } + drmmode_crtc->flip_pending = TRUE; drm_queue_seq = 0; } @@ -2627,6 +2690,10 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, if (flipdata->flip_count > 0) return TRUE; +flip_error: + xf86DrvMsg(scrn->scrnIndex, X_WARNING, "flip queue failed: %s\n", + strerror(errno)); + error: if (flipdata && flipdata->flip_count <= 1) { drmModeRmFB(pAMDGPUEnt->fd, drmmode->fb_id); diff --git a/src/drmmode_display.h b/src/drmmode_display.h index 2c4a869..639b3fb 100644 --- a/src/drmmode_display.h +++ b/src/drmmode_display.h @@ -130,6 +130,16 @@ enum drmmode_flip_sync { }; +extern int drmmode_page_flip_target_absolute(AMDGPUEntPtr pAMDGPUEnt, + drmmode_crtc_private_ptr drmmode_crtc, + int fb_id, uint32_t flags, + uintptr_t drm_queue_seq, + uint32_t target_msc); +extern int drmmode_page_flip_target_relative(AMDGPUEntPtr pAMDGPUEnt, + drmmode_crtc_private_ptr drmmode_crtc, + int fb_id, uint32_t flags, + uintptr_t drm_queue_seq, + uint32_t target_msc); extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp); extern void drmmode_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode); extern void drmmode_fini(ScrnInfoPtr pScrn, drmmode_ptr drmmode); @@ -153,7 +163,8 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client, PixmapPtr new_front, uint64_t id, void *data, int ref_crtc_hw_id, amdgpu_drm_handler_proc handler, amdgpu_drm_abort_proc abort, - enum drmmode_flip_sync flip_sync); + enum drmmode_flip_sync flip_sync, + uint32_t target_msc); int drmmode_crtc_get_ust_msc(xf86CrtcPtr crtc, CARD64 *ust, CARD64 *msc); int drmmode_get_current_ust(int drm_fd, CARD64 * ust); -- 2.10.2