summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/drmmode_display.c61
-rw-r--r--src/drmmode_display.h12
-rw-r--r--src/radeon_kms.c27
-rw-r--r--src/radeon_present.c75
4 files changed, 152 insertions, 23 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 1ce58d1e..90588671 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -612,6 +612,14 @@ error:
static void
radeon_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;
@@ -2429,7 +2437,8 @@ drmmode_flip_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec, void *even
drmmode_fb_reference(pRADEONEnt->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(pRADEONEnt->fd,
&drmmode_crtc->flip_pending, NULL);
}
@@ -2998,13 +3007,16 @@ Bool radeon_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 = radeon_drm_queue_alloc(crtc, client, id,
flipdata,
@@ -3016,10 +3028,39 @@ Bool radeon_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 = radeon_pixmap_get_fb(drmmode_crtc->scanout[scanout_id].pixmap);
+ if (!fb) {
+ ErrorF("Failed to get FB for TearFree flip\n");
+ goto error;
+ }
+
+ radeon_scanout_do_update(crtc, scanout_id,
+ &new_front->drawable, &extents);
+
+ drmmode_crtc_wait_pending_event(drmmode_crtc, pRADEONEnt->fd,
+ drmmode_crtc->scanout_update_pending);
+ }
+
if (crtc == ref_crtc) {
if (drmmode_page_flip_target_absolute(pRADEONEnt,
drmmode_crtc,
- flipdata->fb->handle,
+ fb->handle,
flip_flags,
drm_queue_seq,
target_msc) != 0)
@@ -3027,14 +3068,20 @@ Bool radeon_do_pageflip(ScrnInfoPtr scrn, ClientPtr client,
} else {
if (drmmode_page_flip_target_relative(pRADEONEnt,
drmmode_crtc,
- flipdata->fb->handle,
+ fb->handle,
flip_flags,
drm_queue_seq, 0) != 0)
goto flip_error;
}
- drmmode_fb_reference(pRADEONEnt->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(pRADEONEnt->fd,
+ &drmmode_crtc->flip_pending, fb);
drm_queue_seq = 0;
}
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index 13f301f7..a6db87f8 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -85,6 +85,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;
@@ -106,6 +107,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 {
@@ -146,7 +155,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);
}
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index 17902334..7febf148 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -44,6 +44,10 @@
#include "atipciids.h"
+#if HAVE_PRESENT_H
+#include <present.h>
+#endif
+
/* DPMS */
#ifdef HAVE_XEXTPROTO_71
#include <X11/extensions/dpmsconst.h>
@@ -779,6 +783,15 @@ radeon_prime_scanout_flip_handler(xf86CrtcPtr crtc, uint32_t msc, uint64_t usec,
drmmode_fb_reference(pRADEONEnt->fd, &drmmode_crtc->fb,
drmmode_crtc->flip_pending);
radeon_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
@@ -1001,10 +1014,14 @@ radeon_scanout_update_handler(xf86CrtcPtr crtc, uint32_t frame, uint64_t usec,
ScreenPtr screen = crtc->scrn->pScreen;
RegionPtr region = DamageRegion(drmmode_crtc->scanout_damage);
- radeon_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 (radeon_scanout_do_update(crtc, drmmode_crtc->scanout_id,
+ &screen->GetWindowPixmap(screen->root)->drawable,
+ &region->extents))
+ RegionEmpty(region);
+ }
radeon_scanout_update_abort(crtc, event_data);
}
@@ -1021,6 +1038,7 @@ radeon_scanout_update(xf86CrtcPtr xf86_crtc)
if (!xf86_crtc->enabled ||
drmmode_crtc->scanout_update_pending ||
+ drmmode_crtc->flip_pending ||
drmmode_crtc->dpms_mode != DPMSModeOn)
return;
@@ -1088,6 +1106,7 @@ radeon_scanout_flip(ScreenPtr pScreen, RADEONInfoPtr info,
unsigned scanout_id;
if (drmmode_crtc->scanout_update_pending ||
+ drmmode_crtc->flip_pending ||
drmmode_crtc->dpms_mode != DPMSModeOn)
return;
diff --git a/src/radeon_present.c b/src/radeon_present.c
index c7dde0ec..176853d9 100644
--- a/src/radeon_present.c
+++ b/src/radeon_present.c
@@ -52,6 +52,7 @@ static present_screen_info_rec radeon_present_screen_info;
struct radeon_present_vblank_event {
uint64_t event_id;
+ Bool vblank_for_flip;
Bool unflip;
};
@@ -119,9 +120,26 @@ static void
radeon_present_vblank_handler(xf86CrtcPtr crtc, unsigned int msc,
uint64_t usec, void *data)
{
+ drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private;
struct radeon_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
radeon_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 radeon_present_vblank_event *event;
uintptr_t drm_queue_seq;
@@ -152,6 +171,9 @@ radeon_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 = radeon_drm_queue_alloc(xf86_crtc,
RADEON_DRM_QUEUE_CLIENT_DEFAULT,
event_id, event,
@@ -226,8 +248,17 @@ radeon_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;
@@ -240,10 +271,20 @@ static Bool
radeon_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);
RADEONInfoPtr info = RADEONPTR(scrn);
PixmapPtr screen_pixmap;
+ int num_crtcs_on;
+ int i;
+
+ drmmode_crtc->present_flip_expected = FALSE;
+
+ if (!scrn->vtSema)
+ return FALSE;
if (!info->allowPageFlip)
return FALSE;
@@ -262,10 +303,18 @@ radeon_present_check_flip(RRCrtcPtr crtc, WindowPtr window, PixmapPtr pixmap,
radeon_present_get_pixmap_tiling_flags(info, screen_pixmap))
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 radeon_present_check_unflip(scrn);
+ drmmode_crtc->present_flip_expected = TRUE;
+ return TRUE;
}
/*
@@ -304,18 +353,20 @@ static Bool
radeon_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;
RADEONInfoPtr info = RADEONPTR(scrn);
struct radeon_present_vblank_event *event;
- Bool ret;
+ Bool ret = FALSE;
if (!radeon_present_check_flip(crtc, screen->root, pixmap, sync_flip))
- return FALSE;
+ goto out;
event = calloc(1, sizeof(struct radeon_present_vblank_event));
if (!event)
- return FALSE;
+ goto out;
event->event_id = event_id;
@@ -332,6 +383,8 @@ radeon_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;
}
@@ -376,7 +429,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)