summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMichel Dänzer <michel.daenzer@amd.com>2017-08-18 16:57:13 +0900
committerMichel Dänzer <michel@daenzer.net>2017-08-22 18:34:14 +0900
commit8c82878c6ef1b984ba289383dc17152192c916ee (patch)
tree50129f6ca90ecdeb3608522b47e51efe1a0f4139
parentd8e8f0107bb3e83a787917f4db16a7a54ce4768b (diff)
Always allow Present page flipping with TearFree
Even if TearFree is active for the the CRTC we're synchronizing to. In that case, for Present flips synchronized to vertical blank, the other scanout buffer is immediately synchronized and flipped to during the target vertical blank period. For Present flips not synchronized to vertical blank, we simply use the MSC and timestamp values of the last vertical blank period for timing purposes, and let the normal TearFree mechanism handle display updates. (Ported from radeon commit 4445765af5b97d0cfd10889fe6d6f58f2ce85659) Reviewed-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--src/amdgpu_kms.c27
-rw-r--r--src/amdgpu_present.c75
-rw-r--r--src/drmmode_display.c61
-rw-r--r--src/drmmode_display.h12
4 files changed, 152 insertions, 23 deletions
diff --git a/src/amdgpu_kms.c b/src/amdgpu_kms.c
index aedb3f0..b0f1a3d 100644
--- a/src/amdgpu_kms.c
+++ b/src/amdgpu_kms.c
@@ -41,6 +41,10 @@
#include "shadow.h"
#include <xf86Priv.h>
+#if HAVE_PRESENT_H
+#include <present.h>
+#endif
+
/* DPMS */
#ifdef HAVE_XEXTPROTO_71
#include <X11/extensions/dpmsconst.h>
@@ -681,6 +685,15 @@ amdgpu_prime_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
drmmode_crtc->flip_pending);
amdgpu_prime_scanout_flip_abort(crtc, event_data);
+
+#ifdef HAVE_PRESENT_H
+ if (drmmode_crtc->present_vblank_event_id) {
+ present_event_notify(drmmode_crtc->present_vblank_event_id,
+ drmmode_crtc->present_vblank_usec,
+ drmmode_crtc->present_vblank_msc);
+ drmmode_crtc->present_vblank_event_id = 0;
+ }
+#endif
}
static void
@@ -895,10 +908,14 @@ amdgpu_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
ScreenPtr screen = crtc->scrn->pScreen;
RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
- amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
- &screen->GetWindowPixmap(screen->root)->drawable,
- &region->extents);
- RegionEmpty(region);
+ if (crtc->enabled &&
+ !drmmode_crtc->flip_pending &&
+ drmmode_crtc->dpms_mode == DPMSModeOn) {
+ if (amdgpu_scanout_do_update(crtc, drmmode_crtc->scanout_id,
+ &screen->GetWindowPixmap(screen->root)->drawable,
+ &region->extents))
+ RegionEmpty(region);
+ }
amdgpu_scanout_update_abort(crtc, event_data);
}
@@ -915,6 +932,7 @@ amdgpu_scanout_update(xf86CrtcPtr xf86_crtc)
if (!xf86_crtc->enabled ||
drmmode_crtc->scanout_update_pending ||
+ drmmode_crtc->flip_pending ||
drmmode_crtc->dpms_mode != DPMSModeOn)
return;
@@ -982,6 +1000,7 @@ amdgpu_scanout_flip(ScreenPtr pScreen, AMDGPUInfoPtr info,
unsigned scanout_id;
if (drmmode_crtc->scanout_update_pending ||
+ drmmode_crtc->flip_pending ||
drmmode_crtc->dpms_mode != DPMSModeOn)
return;
diff --git a/src/amdgpu_present.c b/src/amdgpu_present.c
index c7fc402..cef93c0 100644
--- a/src/amdgpu_present.c
+++ b/src/amdgpu_present.c
@@ -52,6 +52,7 @@ static present_screen_info_rec amdgpu_present_screen_info;
struct amdgpu_present_vblank_event {
uint64_t event_id;
+ Bool vblank_for_flip;
Bool unflip;
};
@@ -119,9 +120,26 @@ static void
amdgpu_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc,
uint64_t usec, void *data)
{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
struct amdgpu_present_vblank_event *event = data;
- present_event_notify(event->event_id, usec, msc);
+ if (event->vblank_for_flip &&
+ drmmode_crtc->tear_free &&
+ drmmode_crtc->scanout_update_pending) {
+ if (drmmode_crtc->present_vblank_event_id != 0) {
+ xf86DrvMsg(crtc->scrn->scrnIndex, X_WARNING,
+ "Need to handle previously deferred vblank event\n");
+ present_event_notify(drmmode_crtc->present_vblank_event_id,
+ drmmode_crtc->present_vblank_usec,
+ drmmode_crtc->present_vblank_msc);
+ }
+
+ drmmode_crtc->present_vblank_event_id = event->event_id;
+ drmmode_crtc->present_vblank_msc = msc;
+ drmmode_crtc->present_vblank_usec = usec;
+ } else
+ present_event_notify(event->event_id, usec, msc);
+
free(event);
}
@@ -144,6 +162,7 @@ static int
amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
{
xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
ScreenPtr screen = crtc->pScreen;
struct amdgpu_present_vblank_event *event;
uintptr_t drm_queue_seq;
@@ -152,6 +171,9 @@ amdgpu_present_queue_vblank(RRCrtcPtr crtc, uint64_t event_id, uint64_t msc)
if (!event)
return BadAlloc;
event->event_id = event_id;
+ event->vblank_for_flip = drmmode_crtc->present_flip_expected;
+ drmmode_crtc->present_flip_expected = FALSE;
+
drm_queue_seq = amdgpu_drm_queue_alloc(xf86_crtc,
AMDGPU_DRM_QUEUE_CLIENT_DEFAULT,
event_id, event,
@@ -211,8 +233,17 @@ amdgpu_present_check_unflip(ScrnInfoPtr scrn)
return FALSE;
for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) {
- if (drmmode_crtc_can_flip(config->crtc[i]))
- num_crtcs_on++;
+ xf86CrtcPtr crtc = config->crtc[i];
+
+ if (drmmode_crtc_can_flip(crtc)) {
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
+
+ if (drmmode_crtc->flip_pending)
+ return FALSE;
+
+ if (!drmmode_crtc->tear_free)
+ num_crtcs_on++;
+ }
}
return num_crtcs_on > 0;
@@ -225,9 +256,19 @@ static Bool
amdgpu_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
Bool sync_flip)
{
+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
ScreenPtr screen = window->drawable.pScreen;
- ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ ScrnInfoPtr scrn = xf86_crtc->scrn;
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
AMDGPUInfoPtr info = AMDGPUPTR(scrn);
+ int num_crtcs_on;
+ int i;
+
+ drmmode_crtc->present_flip_expected = FALSE;
+
+ if (!scrn->vtSema)
+ return FALSE;
if (!info->allowPageFlip)
return FALSE;
@@ -245,10 +286,18 @@ amdgpu_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
amdgpu_pixmap_get_tiling_info(screen->GetScreenPixmap(screen)))
return FALSE;
- if (!drmmode_crtc_can_flip(crtc->devPrivate))
+ for (i = 0, num_crtcs_on = 0; i < config->num_crtc; i++) {
+ if (drmmode_crtc_can_flip(config->crtc[i]))
+ num_crtcs_on++;
+ else if (config->crtc[i] == crtc->devPrivate)
+ return FALSE;
+ }
+
+ if (num_crtcs_on == 0)
return FALSE;
- return amdgpu_present_check_unflip(scrn);
+ drmmode_crtc->present_flip_expected = TRUE;
+ return TRUE;
}
/*
@@ -287,18 +336,20 @@ static Bool
amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
PixmapPtr pixmap, Bool sync_flip)
{
+ xf86CrtcPtr xf86_crtc = crtc->devPrivate;
+ drmmode_crtc_private_ptr drmmode_crtc = xf86_crtc->driver_private;
ScreenPtr screen = crtc->pScreen;
- ScrnInfoPtr scrn = xf86ScreenToScrn(screen);
+ ScrnInfoPtr scrn = xf86_crtc->scrn;
AMDGPUInfoPtr info = AMDGPUPTR(scrn);
struct amdgpu_present_vblank_event *event;
- Bool ret;
+ Bool ret = FALSE;
if (!amdgpu_present_check_flip(crtc, screen->root, pixmap, sync_flip))
- return FALSE;
+ goto out;
event = calloc(1, sizeof(struct amdgpu_present_vblank_event));
if (!event)
- return FALSE;
+ goto out;
event->event_id = event_id;
@@ -315,6 +366,8 @@ amdgpu_present_flip(RRCrtcPtr crtc, uint64_t event_id, uint64_t target_msc,
else
info->drmmode.present_flipping = TRUE;
+ out:
+ drmmode_crtc->present_flip_expected = FALSE;
return ret;
}
@@ -358,7 +411,7 @@ modeset:
xf86CrtcPtr crtc = config->crtc[i];
drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
- if (!crtc->enabled)
+ if (!crtc->enabled || drmmode_crtc->tear_free)
continue;
if (drmmode_crtc->dpms_mode == DPMSModeOn)
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index fa19fd7..edd955e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -550,6 +550,14 @@ error:
static void
amdgpu_screen_damage_report(DamagePtr damage, RegionPtr region, void *closure)
{
+ drmmode_crtc_private_ptr drmmode_crtc = closure;
+
+ if (drmmode_crtc->ignore_damage) {
+ RegionEmpty(&damage->damage);
+ drmmode_crtc->ignore_damage = FALSE;
+ return;
+ }
+
/* Only keep track of the extents */
RegionUninit(&damage->damage);
damage->damage.data = NULL;
@@ -2253,7 +2261,8 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->fb,
flipdata->fb);
- if (drmmode_crtc->flip_pending == flipdata->fb) {
+ if (drmmode_crtc->tear_free ||
+ drmmode_crtc->flip_pending == flipdata->fb) {
drmmode_fb_reference(pAMDGPUEnt->fd,
&drmmode_crtc->flip_pending, NULL);
}
@@ -2798,13 +2807,16 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
flipdata->fe_crtc = ref_crtc;
for (i = 0; i < config->num_crtc; i++) {
+ struct drmmode_fb *fb = flipdata->fb;
+
crtc = config->crtc[i];
+ drmmode_crtc = crtc->driver_private;
- if (!drmmode_crtc_can_flip(crtc))
+ if (!drmmode_crtc_can_flip(crtc) ||
+ (drmmode_crtc->tear_free && crtc != ref_crtc))
continue;
flipdata->flip_count++;
- drmmode_crtc = crtc->driver_private;
drm_queue_seq = amdgpu_drm_queue_alloc(crtc, client, id,
flipdata,
@@ -2816,10 +2828,39 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
goto error;
}
+ if (drmmode_crtc->tear_free) {
+ BoxRec extents = { .x1 = 0, .y1 = 0,
+ .x2 = new_front->drawable.width,
+ .y2 = new_front->drawable.height };
+ int scanout_id = drmmode_crtc->scanout_id ^ 1;
+
+ if (flip_sync == FLIP_ASYNC) {
+ if (!drmmode_wait_vblank(crtc,
+ DRM_VBLANK_RELATIVE |
+ DRM_VBLANK_EVENT,
+ 0, drm_queue_seq,
+ NULL, NULL))
+ goto flip_error;
+ goto next;
+ }
+
+ fb = amdgpu_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+ if (!fb) {
+ ErrorF("Failed to get FB for TearFree flip\n");
+ goto error;
+ }
+
+ amdgpu_scanout_do_update(crtc, scanout_id,
+ &new_front->drawable, &extents);
+
+ drmmode_crtc_wait_pending_event(drmmode_crtc, pAMDGPUEnt->fd,
+ drmmode_crtc->scanout_update_pending);
+ }
+
if (crtc == ref_crtc) {
if (drmmode_page_flip_target_absolute(pAMDGPUEnt,
drmmode_crtc,
- flipdata->fb->handle,
+ fb->handle,
flip_flags,
drm_queue_seq,
target_msc) != 0)
@@ -2827,14 +2868,20 @@ Bool amdgpu_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
} else {
if (drmmode_page_flip_target_relative(pAMDGPUEnt,
drmmode_crtc,
- flipdata->fb->handle,
+ fb->handle,
flip_flags,
drm_queue_seq, 0) != 0)
goto flip_error;
}
- drmmode_fb_reference(pAMDGPUEnt->fd, &drmmode_crtc->flip_pending,
- flipdata->fb);
+ if (drmmode_crtc->tear_free) {
+ drmmode_crtc->scanout_id ^= 1;
+ drmmode_crtc->ignore_damage = TRUE;
+ }
+
+ next:
+ drmmode_fb_reference(pAMDGPUEnt->fd,
+ &drmmode_crtc->flip_pending, fb);
drm_queue_seq = 0;
}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index b5788e2..1a6454c 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -81,6 +81,7 @@ typedef struct {
struct drmmode_scanout rotate;
struct drmmode_scanout scanout[2];
DamagePtr scanout_damage;
+ Bool ignore_damage;
RegionRec scanout_last_region;
unsigned scanout_id;
Bool scanout_update_pending;
@@ -100,6 +101,14 @@ typedef struct {
struct drmmode_fb *flip_pending;
/* The FB currently being scanned out by this CRTC, if any */
struct drmmode_fb *fb;
+
+#ifdef HAVE_PRESENT_H
+ /* Deferred processing of Present vblank event */
+ uint64_t present_vblank_event_id;
+ uint64_t present_vblank_usec;
+ unsigned present_vblank_msc;
+ Bool present_flip_expected;
+#endif
} drmmode_crtc_private_rec, *drmmode_crtc_private_ptr;
typedef struct {
@@ -139,7 +148,8 @@ drmmode_crtc_can_flip(xf86CrtcPtr crtc)
return crtc->enabled &&
drmmode_crtc->dpms_mode == DPMSModeOn &&
!drmmode_crtc->rotate.bo &&
- !drmmode_crtc->scanout[drmmode_crtc->scanout_id].bo;
+ (drmmode_crtc->tear_free ||
+ !drmmode_crtc->scanout[drmmode_crtc->scanout_id].bo);
}