summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Deucher <alexdeucher@gmail.com>2011-01-10 18:16:49 -0500
committerAlex Deucher <alexdeucher@gmail.com>2011-01-10 18:16:49 -0500
commite5d0a400d08da2358fac9c2ad12042f125525736 (patch)
treea869dd4be87331d24076cc46c60ef4dffbb5b9f2
parent0e432dff9e06a183acaeb20db29cbd03ff0f4b82 (diff)
parente27e9b4e50ad42885ad2e25be897cdf29aa59712 (diff)
Merge branch 'kms-pflip' of git+ssh://git.freedesktop.org/git/xorg/driver/xf86-video-ati
-rw-r--r--man/radeon.man17
-rw-r--r--src/drmmode_display.c134
-rw-r--r--src/drmmode_display.h12
-rw-r--r--src/evergreen_exa.c21
-rw-r--r--src/r600_exa.c21
-rw-r--r--src/radeon.h8
-rw-r--r--src/radeon_dri2.c278
-rw-r--r--src/radeon_dri2.h2
-rw-r--r--src/radeon_exa.c11
-rw-r--r--src/radeon_kms.c23
10 files changed, 461 insertions, 66 deletions
diff --git a/man/radeon.man b/man/radeon.man
index 609f7672..285cb397 100644
--- a/man/radeon.man
+++ b/man/radeon.man
@@ -266,7 +266,22 @@ to use VRAM for non-essential pixmaps. This option allows us to override the
heuristic. The default is
.B on
with > 32MB VRAM, off with < 32MB.
-
+.TP
+.BI "Option \*qSwapbuffersWait\*q \*q" boolean \*q
+This option controls the behavior of glXSwapBuffers and glXCopySubBufferMESA
+calls by GL applications. If enabled, the calls will avoid tearing by making
+sure the display scanline is outside of the area to be copied before the copy
+occurs. If disabled, no scanline synchronization is performed, meaning tearing
+will likely occur. Note that when enabled, this option can adversely affect
+the framerate of applications that render frames at less than refresh rate.
+.IP
+The default value is
+.B on.
+.TP
+.BI "Option \*qEnablePageFlip\*q \*q" boolean \*q
+Enable DRI2 page flipping. The default is
+.B on.
+Pageflipping is supported on all radeon hardware.
.PP
The following driver
.B Options
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 0a6e338e..9248cb0e 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -29,6 +29,7 @@
#include "config.h"
#endif
+#include <errno.h>
#ifdef XF86DRM_MODE
#include <sys/ioctl.h>
#include "micmap.h"
@@ -266,9 +267,10 @@ drmmode_set_mode_major(xf86CrtcPtr crtc, DisplayModePtr mode,
uint32_t tiling_flags = 0;
int height;
- /* no tiled scanout on r6xx+ yet */
if (info->allowColorTiling) {
- if (info->ChipFamily < CHIP_FAMILY_R600)
+ if (info->ChipFamily >= CHIP_FAMILY_R600)
+ tiling_flags |= RADEON_TILING_MICRO;
+ else
tiling_flags |= RADEON_TILING_MACRO;
}
@@ -1167,9 +1169,10 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height)
if (front_bo)
radeon_bo_wait(front_bo);
- /* no tiled scanout on r6xx+ yet */
if (info->allowColorTiling) {
- if (info->ChipFamily < CHIP_FAMILY_R600)
+ if (info->ChipFamily >= CHIP_FAMILY_R600)
+ tiling_flags |= RADEON_TILING_MICRO;
+ else
tiling_flags |= RADEON_TILING_MACRO;
}
@@ -1278,6 +1281,39 @@ drmmode_vblank_handler(int fd, unsigned int frame, unsigned int tv_sec,
}
static void
+drmmode_flip_handler(int fd, unsigned int frame, unsigned int tv_sec,
+ unsigned int tv_usec, void *event_data)
+{
+ drmmode_flipevtcarrier_ptr flipcarrier = event_data;
+ drmmode_ptr drmmode = flipcarrier->drmmode;
+
+ /* Is this the event whose info shall be delivered to higher level? */
+ if (flipcarrier->dispatch_me) {
+ /* Yes: Cache msc, ust for later delivery. */
+ drmmode->fe_frame = frame;
+ drmmode->fe_tv_sec = tv_sec;
+ drmmode->fe_tv_usec = tv_usec;
+ }
+ free(flipcarrier);
+
+ /* Last crtc completed flip? */
+ drmmode->flip_count--;
+ if (drmmode->flip_count > 0)
+ return;
+
+ /* Release framebuffer */
+ drmModeRmFB(drmmode->fd, drmmode->old_fb_id);
+
+ if (drmmode->event_data == NULL)
+ return;
+
+ /* Deliver cached msc, ust from reference crtc to flip event handler */
+ radeon_dri2_flip_event_handler(drmmode->fe_frame, drmmode->fe_tv_sec,
+ drmmode->fe_tv_usec, drmmode->event_data);
+}
+
+
+static void
drm_wakeup_handler(pointer data, int err, pointer p)
{
drmmode_ptr drmmode = data;
@@ -1320,8 +1356,9 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, drmmode_ptr drmmode, int cpp)
drmmode->flip_count = 0;
drmmode->event_context.version = DRM_EVENT_CONTEXT_VERSION;
drmmode->event_context.vblank_handler = drmmode_vblank_handler;
- drmmode->event_context.page_flip_handler = NULL;
+ drmmode->event_context.page_flip_handler = drmmode_flip_handler;
if (!pRADEONEnt->fd_wakeup_registered && info->dri->pKernelDRMVersion->version_minor >= 4) {
+ drmmode->flip_count = 0;
AddGeneralSocket(drmmode->fd);
RegisterBlockAndWakeupHandlers((BlockHandlerProcPtr)NoopDDA,
drm_wakeup_handler, drmmode);
@@ -1561,4 +1598,91 @@ void drmmode_uevent_fini(ScrnInfoPtr scrn, drmmode_ptr drmmode)
#endif
}
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id)
+{
+ RADEONInfoPtr info = RADEONPTR(scrn);
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private;
+ drmmode_ptr drmmode = drmmode_crtc->drmmode;
+ unsigned int pitch = scrn->displayWidth * info->CurrentLayout.pixel_bytes;
+ int i, old_fb_id;
+ uint32_t tiling_flags = 0;
+ int height;
+ drmmode_flipevtcarrier_ptr flipcarrier;
+
+ if (info->allowColorTiling) {
+ if (info->ChipFamily >= CHIP_FAMILY_R600)
+ tiling_flags |= RADEON_TILING_MICRO;
+ else
+ tiling_flags |= RADEON_TILING_MACRO;
+ }
+
+ pitch = RADEON_ALIGN(pitch, drmmode_get_pitch_align(scrn, info->CurrentLayout.pixel_bytes, tiling_flags));
+ height = RADEON_ALIGN(scrn->virtualY, drmmode_get_height_align(scrn, tiling_flags));
+
+ /*
+ * Create a new handle for the back buffer
+ */
+ old_fb_id = drmmode->fb_id;
+ if (drmModeAddFB(drmmode->fd, scrn->virtualX, height,
+ scrn->depth, scrn->bitsPerPixel, pitch,
+ new_front->handle, &drmmode->fb_id))
+ goto error_out;
+
+ /*
+ * Queue flips on all enabled CRTCs
+ * Note that if/when we get per-CRTC buffers, we'll have to update this.
+ * Right now it assumes a single shared fb across all CRTCs, with the
+ * kernel fixing up the offset of each CRTC as necessary.
+ *
+ * Also, flips queued on disabled or incorrectly configured displays
+ * may never complete; this is a configuration error.
+ */
+ drmmode->fe_frame = 0;
+ drmmode->fe_tv_sec = 0;
+ drmmode->fe_tv_usec = 0;
+
+ for (i = 0; i < config->num_crtc; i++) {
+ if (!config->crtc[i]->enabled)
+ continue;
+
+ drmmode->event_data = data;
+ drmmode->flip_count++;
+ drmmode_crtc = config->crtc[i]->driver_private;
+
+ flipcarrier = calloc(1, sizeof(drmmode_flipevtcarrier_rec));
+ if (!flipcarrier) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue: carrier alloc failed.\n");
+ goto error_undo;
+ }
+
+ /* Only the reference crtc will finally deliver its page flip
+ * completion event. All other crtc's events will be discarded.
+ */
+ flipcarrier->dispatch_me = (drmmode_crtc->hw_id == ref_crtc_hw_id);
+ flipcarrier->drmmode = drmmode;
+
+ if (drmModePageFlip(drmmode->fd, drmmode_crtc->mode_crtc->crtc_id,
+ drmmode->fb_id, DRM_MODE_PAGE_FLIP_EVENT, flipcarrier)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: %s\n", strerror(errno));
+ free(flipcarrier);
+ goto error_undo;
+ }
+ }
+
+ drmmode->old_fb_id = old_fb_id;
+ return TRUE;
+
+error_undo:
+ drmModeRmFB(drmmode->fd, drmmode->fb_id);
+ drmmode->fb_id = old_fb_id;
+
+error_out:
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "Page flip failed: %s\n",
+ strerror(errno));
+ return FALSE;
+}
+
#endif
diff --git a/src/drmmode_display.h b/src/drmmode_display.h
index e6bfd50a..548907bb 100644
--- a/src/drmmode_display.h
+++ b/src/drmmode_display.h
@@ -39,6 +39,7 @@
typedef struct {
int fd;
unsigned fb_id;
+ unsigned old_fb_id;
drmModeResPtr mode_res;
drmModeFBPtr mode_fb;
int cpp;
@@ -50,9 +51,18 @@ typedef struct {
#endif
drmEventContext event_context;
int flip_count;
+ void *event_data;
+ unsigned int fe_frame;
+ unsigned int fe_tv_sec;
+ unsigned int fe_tv_usec;
} drmmode_rec, *drmmode_ptr;
typedef struct {
+ drmmode_ptr drmmode;
+ Bool dispatch_me;
+} drmmode_flipevtcarrier_rec, *drmmode_flipevtcarrier_ptr;
+
+typedef struct {
drmmode_ptr drmmode;
drmModeCrtcPtr mode_crtc;
int hw_id;
@@ -99,6 +109,8 @@ extern int drmmode_get_height_align(ScrnInfoPtr scrn, uint32_t tiling);
extern int drmmode_get_pitch_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
extern int drmmode_get_base_align(ScrnInfoPtr scrn, int bpe, uint32_t tiling);
+Bool radeon_do_pageflip(ScrnInfoPtr scrn, struct radeon_bo *new_front, void *data, int ref_crtc_hw_id);
+
#endif
#endif
diff --git a/src/evergreen_exa.c b/src/evergreen_exa.c
index c6ef33d4..0fe00d80 100644
--- a/src/evergreen_exa.c
+++ b/src/evergreen_exa.c
@@ -1647,22 +1647,29 @@ EVERGREENDownloadFromScreen(PixmapPtr pSrc, int x, int y, int w,
Bool flush = FALSE;
Bool r;
struct r600_accel_object src_obj, dst_obj;
+ uint32_t tiling_flags = 0, pitch = 0;
if (bpp < 8)
return FALSE;
driver_priv = exaGetPixmapDriverPrivate(pSrc);
+ ret = radeon_bo_get_tiling(driver_priv->bo, &tiling_flags, &pitch);
+ if (ret)
+ ErrorF("radeon_bo_get_tiling failed\n");
+
/* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
copy_src = driver_priv->bo;
copy_pitch = pSrc->devKind;
- if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
- src_domain = radeon_bo_get_src_domain(driver_priv->bo);
- if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
- (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
- src_domain = 0;
- else /* A write may be scheduled */
- flush = TRUE;
+ if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
+ if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
+ src_domain = radeon_bo_get_src_domain(driver_priv->bo);
+ if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
+ (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
+ src_domain = 0;
+ else /* A write may be scheduled */
+ flush = TRUE;
+ }
}
if (!src_domain)
diff --git a/src/r600_exa.c b/src/r600_exa.c
index 15db42ac..5dfc770e 100644
--- a/src/r600_exa.c
+++ b/src/r600_exa.c
@@ -1895,22 +1895,29 @@ R600DownloadFromScreenCS(PixmapPtr pSrc, int x, int y, int w,
Bool flush = FALSE;
Bool r;
struct r600_accel_object src_obj, dst_obj;
+ uint32_t tiling_flags = 0, pitch = 0;
if (bpp < 8)
return FALSE;
driver_priv = exaGetPixmapDriverPrivate(pSrc);
+ ret = radeon_bo_get_tiling(driver_priv->bo, &tiling_flags, &pitch);
+ if (ret)
+ ErrorF("radeon_bo_get_tiling failed\n");
+
/* If we know the BO won't end up in VRAM anyway, don't bother with a scratch */
copy_src = driver_priv->bo;
copy_pitch = pSrc->devKind;
- if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
- src_domain = radeon_bo_get_src_domain(driver_priv->bo);
- if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
- (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
- src_domain = 0;
- else /* A write may be scheduled */
- flush = TRUE;
+ if (!(tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))) {
+ if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
+ src_domain = radeon_bo_get_src_domain(driver_priv->bo);
+ if ((src_domain & (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM)) ==
+ (RADEON_GEM_DOMAIN_GTT | RADEON_GEM_DOMAIN_VRAM))
+ src_domain = 0;
+ else /* A write may be scheduled */
+ flush = TRUE;
+ }
}
if (!src_domain)
diff --git a/src/radeon.h b/src/radeon.h
index 7f55feec..4da9bf76 100644
--- a/src/radeon.h
+++ b/src/radeon.h
@@ -224,7 +224,8 @@ typedef enum {
OPTION_FORCE_LOW_POWER,
OPTION_DYNAMIC_PM,
OPTION_NEW_PLL,
- OPTION_ZAPHOD_HEADS
+ OPTION_ZAPHOD_HEADS,
+ OPTION_SWAPBUFFERS_WAIT
} RADEONOpts;
@@ -1079,6 +1080,11 @@ typedef struct {
struct radeon_bo *bicubic_bo;
void *bicubic_memory;
int bicubic_offset;
+ /* kms pageflipping */
+ Bool allowPageFlip;
+
+ /* Perform vsync'ed SwapBuffers? */
+ Bool swapBuffersWait;
} RADEONInfoRec, *RADEONInfoPtr;
#define RADEONWaitForFifo(pScrn, entries) \
diff --git a/src/radeon_dri2.c b/src/radeon_dri2.c
index f2ea0bb4..e8e16ff9 100644
--- a/src/radeon_dri2.c
+++ b/src/radeon_dri2.c
@@ -82,6 +82,10 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
struct radeon_exa_pixmap_priv *driver_priv;
int i, r, need_enlarge = 0;
int flags = 0;
+ unsigned front_width;
+
+ pixmap = screen->GetScreenPixmap(screen);
+ front_width = pixmap->drawable.width;
buffers = calloc(count, sizeof *buffers);
if (buffers == NULL) {
@@ -162,12 +166,18 @@ radeon_dri2_create_buffers(DrawablePtr drawable,
drawable->depth,
flags);
- } else
+ } else {
+ unsigned aligned_width = drawable->width;
+
+ if (aligned_width == front_width)
+ aligned_width = pScrn->virtualX;
+
pixmap = (*pScreen->CreatePixmap)(pScreen,
- drawable->width,
+ aligned_width,
drawable->height,
drawable->depth,
flags);
+ }
}
if (attachments[i] == DRI2BufferDepth) {
@@ -206,6 +216,10 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
struct radeon_exa_pixmap_priv *driver_priv;
int r, need_enlarge = 0;
int flags;
+ unsigned front_width;
+
+ pixmap = pScreen->GetScreenPixmap(pScreen);
+ front_width = pixmap->drawable.width;
buffers = calloc(1, sizeof *buffers);
if (buffers == NULL) {
@@ -287,12 +301,18 @@ radeon_dri2_create_buffer(DrawablePtr drawable,
(format != 0)?format:drawable->depth,
flags);
- } else
+ } else {
+ unsigned aligned_width = drawable->width;
+
+ if (aligned_width == front_width)
+ aligned_width = pScrn->virtualX;
+
pixmap = (*pScreen->CreatePixmap)(pScreen,
- drawable->width,
+ aligned_width,
drawable->height,
(format != 0)?format:drawable->depth,
flags);
+ }
}
if (attachment == DRI2BufferDepth) {
@@ -423,7 +443,9 @@ radeon_dri2_copy_region(DrawablePtr drawable,
}
vsync = info->accel_state->vsync;
- info->accel_state->vsync = TRUE;
+
+ /* Driver option "SwapbuffersWait" defines if we vsync DRI2 copy-swaps. */
+ info->accel_state->vsync = info->swapBuffersWait;
(*gc->ops->CopyArea)(src_drawable, dst_drawable, gc,
0, 0, drawable->width, drawable->height, 0, 0);
@@ -549,12 +571,124 @@ radeon_dri2_unref_buffer(BufferPtr buffer)
}
}
+static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
+{
+ ScreenPtr pScreen = pDraw->pScreen;
+ ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
+ xf86CrtcPtr crtc;
+ int crtc_id = -1;
+
+ crtc = radeon_pick_best_crtc(pScrn,
+ pDraw->x,
+ pDraw->x + pDraw->width,
+ pDraw->y,
+ pDraw->y + pDraw->height);
+
+ /* Make sure the CRTC is valid and this is the real front buffer */
+ if (crtc != NULL && !crtc->rotatedData) {
+ crtc_id = drmmode_get_crtc_id(crtc);
+ }
+ return crtc_id;
+}
+
+static Bool
+radeon_dri2_schedule_flip(ScrnInfoPtr scrn, ClientPtr client,
+ DrawablePtr draw, DRI2BufferPtr front,
+ DRI2BufferPtr back, DRI2SwapEventPtr func,
+ void *data, unsigned int target_msc)
+{
+ struct dri2_buffer_priv *back_priv;
+ struct radeon_exa_pixmap_priv *exa_priv;
+ DRI2FrameEventPtr flip_info;
+
+ /* Main crtc for this drawable shall finally deliver pageflip event. */
+ int ref_crtc_hw_id = radeon_dri2_drawable_crtc(draw);
+
+ flip_info = calloc(1, sizeof(DRI2FrameEventRec));
+ if (!flip_info)
+ return FALSE;
+
+ flip_info->drawable_id = draw->id;
+ flip_info->client = client;
+ flip_info->type = DRI2_SWAP;
+ flip_info->event_complete = func;
+ flip_info->event_data = data;
+ flip_info->frame = target_msc;
+
+ xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+ "%s:%d fevent[%p]\n", __func__, __LINE__, flip_info);
+
+ /* Page flip the full screen buffer */
+ back_priv = back->driverPrivate;
+ exa_priv = exaGetPixmapDriverPrivate(back_priv->pixmap);
+
+ return radeon_do_pageflip(scrn, exa_priv->bo, flip_info, ref_crtc_hw_id);
+}
+
+static Bool
+can_exchange(DRI2BufferPtr front, DRI2BufferPtr back)
+{
+ struct dri2_buffer_priv *front_priv = front->driverPrivate;
+ struct dri2_buffer_priv *back_priv = back->driverPrivate;
+ PixmapPtr front_pixmap = front_priv->pixmap;
+ PixmapPtr back_pixmap = back_priv->pixmap;
+
+ if (front_pixmap->drawable.width != back_pixmap->drawable.width)
+ return FALSE;
+
+ if (front_pixmap->drawable.height != back_pixmap->drawable.height)
+ return FALSE;
+
+ if (front_pixmap->drawable.bitsPerPixel != back_pixmap->drawable.bitsPerPixel)
+ return FALSE;
+
+ if (front_pixmap->devKind != back_pixmap->devKind)
+ return FALSE;
+
+ return TRUE;
+}
+
+static void
+radeon_dri2_exchange_buffers(DrawablePtr draw, DRI2BufferPtr front, DRI2BufferPtr back)
+{
+ struct dri2_buffer_priv *front_priv = front->driverPrivate;
+ struct dri2_buffer_priv *back_priv = back->driverPrivate;
+ struct radeon_exa_pixmap_priv *front_radeon, *back_radeon;
+ ScreenPtr screen;
+ RADEONInfoPtr info;
+ struct radeon_bo *bo;
+ int tmp;
+
+ /* Swap BO names so DRI works */
+ tmp = front->name;
+ front->name = back->name;
+ back->name = tmp;
+
+ /* Swap pixmap bos */
+ front_radeon = exaGetPixmapDriverPrivate(front_priv->pixmap);
+ back_radeon = exaGetPixmapDriverPrivate(back_priv->pixmap);
+ bo = back_radeon->bo;
+ back_radeon->bo = front_radeon->bo;
+ front_radeon->bo = bo;
+
+ /* Do we need to update the Screen? */
+ screen = draw->pScreen;
+ info = RADEONPTR(xf86Screens[screen->myNum]);
+ if (front_radeon->bo == info->front_bo) {
+ radeon_bo_unref(info->front_bo);
+ info->front_bo = back_radeon->bo;
+ radeon_bo_ref(info->front_bo);
+ front_radeon = exaGetPixmapDriverPrivate(screen->GetScreenPixmap(screen));
+ front_radeon->bo = bo;
+ }
+}
+
void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data)
{
DRI2FrameEventPtr event = event_data;
+ RADEONInfoPtr info;
DrawablePtr drawable;
- ClientPtr client;
ScreenPtr screen;
ScrnInfoPtr scrn;
int status;
@@ -563,7 +697,7 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
RegionRec region;
if (!event->valid)
- goto cleanup;
+ goto cleanup;
status = dixLookupDrawable(&drawable, event->drawable_id, serverClient,
M_ANY, DixWriteAccess);
@@ -572,25 +706,46 @@ void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
screen = drawable->pScreen;
scrn = xf86Screens[screen->myNum];
- client = event->client;
+ info = RADEONPTR(scrn);
switch (event->type) {
case DRI2_FLIP:
+ if (info->allowPageFlip &&
+ DRI2CanFlip(drawable) &&
+ can_exchange(event->front, event->back) &&
+ radeon_dri2_schedule_flip(scrn,
+ event->client,
+ drawable,
+ event->front,
+ event->back,
+ event->event_complete,
+ event->event_data,
+ event->frame)) {
+ radeon_dri2_exchange_buffers(drawable, event->front, event->back);
+ break;
+ }
+ /* else fall through to exchange/blit */
case DRI2_SWAP:
- box.x1 = 0;
- box.y1 = 0;
- box.x2 = drawable->width;
- box.y2 = drawable->height;
- REGION_INIT(pScreen, &region, &box, 0);
- radeon_dri2_copy_region(drawable, &region, event->front, event->back);
- swap_type = DRI2_BLIT_COMPLETE;
-
- DRI2SwapComplete(client, drawable, frame, tv_sec, tv_usec,
+ if (DRI2CanExchange(drawable) &&
+ can_exchange(event->front, event->back)) {
+ radeon_dri2_exchange_buffers(drawable, event->front, event->back);
+ swap_type = DRI2_EXCHANGE_COMPLETE;
+ } else {
+ box.x1 = 0;
+ box.y1 = 0;
+ box.x2 = drawable->width;
+ box.y2 = drawable->height;
+ REGION_INIT(pScreen, &region, &box, 0);
+ radeon_dri2_copy_region(drawable, &region, event->front, event->back);
+ swap_type = DRI2_BLIT_COMPLETE;
+ }
+
+ DRI2SwapComplete(event->client, drawable, frame, tv_sec, tv_usec,
swap_type, event->event_complete, event->event_data);
break;
case DRI2_WAITMSC:
- DRI2WaitMSCComplete(client, drawable, frame, tv_sec, tv_usec);
+ DRI2WaitMSCComplete(event->client, drawable, frame, tv_sec, tv_usec);
break;
default:
/* Unknown type */
@@ -607,26 +762,6 @@ cleanup:
free(event);
}
-static int radeon_dri2_drawable_crtc(DrawablePtr pDraw)
-{
- ScreenPtr pScreen = pDraw->pScreen;
- ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum];
- xf86CrtcPtr crtc;
- int crtc_id = -1;
-
- crtc = radeon_pick_best_crtc(pScrn,
- pDraw->x,
- pDraw->x + pDraw->width,
- pDraw->y,
- pDraw->y + pDraw->height);
-
- /* Make sure the CRTC is valid and this is the real front buffer */
- if (crtc != NULL && !crtc->rotatedData) {
- crtc_id = drmmode_get_crtc_id(crtc);
- }
- return crtc_id;
-}
-
/*
* Get current frame count and frame count timestamp, based on drawable's
* crtc.
@@ -638,7 +773,7 @@ static int radeon_dri2_get_msc(DrawablePtr draw, CARD64 *ust, CARD64 *msc)
RADEONInfoPtr info = RADEONPTR(scrn);
drmVBlank vbl;
int ret;
- int crtc= radeon_dri2_drawable_crtc(draw);
+ int crtc = radeon_dri2_drawable_crtc(draw);
/* Drawable not displayed, make up a value */
if (crtc == -1) {
@@ -796,6 +931,59 @@ out_complete:
return TRUE;
}
+void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
+ unsigned int tv_usec, void *event_data)
+{
+ DRI2FrameEventPtr flip = event_data;
+ DrawablePtr drawable;
+ ScreenPtr screen;
+ ScrnInfoPtr scrn;
+ int status;
+ PixmapPtr pixmap;
+
+ status = dixLookupDrawable(&drawable, flip->drawable_id, serverClient,
+ M_ANY, DixWriteAccess);
+ if (status != Success) {
+ free(flip);
+ return;
+ }
+
+ screen = drawable->pScreen;
+ scrn = xf86Screens[screen->myNum];
+
+ pixmap = screen->GetScreenPixmap(screen);
+ xf86DrvMsgVerb(scrn->scrnIndex, X_INFO, RADEON_LOGLEVEL_DEBUG,
+ "%s:%d fevent[%p] width %d pitch %d (/4 %d)\n",
+ __func__, __LINE__, flip, pixmap->drawable.width, pixmap->devKind, pixmap->devKind/4);
+
+ /* We assume our flips arrive in order, so we don't check the frame */
+ switch (flip->type) {
+ case DRI2_SWAP:
+ /* Check for too small vblank count of pageflip completion, taking wraparound
+ * into account. This usually means some defective kms pageflip completion,
+ * causing wrong (msc, ust) return values and possible visual corruption.
+ */
+ if ((frame < flip->frame) && (flip->frame - frame < 5)) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "%s: Pageflip completion event has impossible msc %d < target_msc %d\n",
+ __func__, frame, flip->frame);
+ /* All-Zero values signal failure of (msc, ust) timestamping to client. */
+ frame = tv_sec = tv_usec = 0;
+ }
+
+ DRI2SwapComplete(flip->client, drawable, frame, tv_sec, tv_usec,
+ DRI2_FLIP_COMPLETE, flip->event_complete,
+ flip->event_data);
+ break;
+ default:
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING, "%s: unknown vblank event received\n", __func__);
+ /* Unknown type */
+ break;
+ }
+
+ free(flip);
+}
+
/*
* ScheduleSwap is responsible for requesting a DRM vblank event for the
* appropriate frame.
@@ -883,6 +1071,15 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
}
current_msc = vbl.reply.sequence;
+
+ /* Flips need to be submitted one frame before */
+ if (info->allowPageFlip &&
+ DRI2CanFlip(draw) &&
+ can_exchange(front, back)) {
+ swap_type = DRI2_FLIP;
+ flip = 1;
+ }
+
swap_info->type = swap_type;
/* Correct target_msc by 'flip' if swap_type == DRI2_FLIP.
@@ -899,9 +1096,6 @@ static int radeon_dri2_schedule_swap(ClientPtr client, DrawablePtr draw,
*/
if (divisor == 0 || current_msc < *target_msc) {
vbl.request.type = DRM_VBLANK_ABSOLUTE | DRM_VBLANK_EVENT;
- if (crtc > 0)
- vbl.request.type |= DRM_VBLANK_SECONDARY;
-
/* If non-pageflipping, but blitting/exchanging, we need to use
* DRM_VBLANK_NEXTONMISS to avoid unreliable timestamping later
* on.
diff --git a/src/radeon_dri2.h b/src/radeon_dri2.h
index 688530f2..79952862 100644
--- a/src/radeon_dri2.h
+++ b/src/radeon_dri2.h
@@ -44,5 +44,7 @@ xf86CrtcPtr radeon_covering_crtc(ScrnInfoPtr pScrn, BoxPtr box,
xf86CrtcPtr desired, BoxPtr crtc_box_ret);
void radeon_dri2_frame_event_handler(unsigned int frame, unsigned int tv_sec,
unsigned int tv_usec, void *event_data);
+void radeon_dri2_flip_event_handler(unsigned int frame, unsigned int tv_sec,
+ unsigned int tv_usec, void *event_data);
#endif
diff --git a/src/radeon_exa.c b/src/radeon_exa.c
index 9c40da79..9df7251e 100644
--- a/src/radeon_exa.c
+++ b/src/radeon_exa.c
@@ -318,6 +318,17 @@ Bool RADEONPrepareAccess_CS(PixmapPtr pPix, int index)
if (!driver_priv)
return FALSE;
+ if (info->ChipFamily >= CHIP_FAMILY_R600) {
+ uint32_t tiling_flags = 0, pitch = 0;
+
+ ret = radeon_bo_get_tiling(driver_priv->bo, &tiling_flags, &pitch);
+ if (ret)
+ return FALSE;
+ /* untile in DFS/UTS */
+ if (tiling_flags & (RADEON_TILING_MACRO | RADEON_TILING_MICRO))
+ return FALSE;
+ }
+
/* if we have more refs than just the BO then flush */
if (radeon_bo_is_referenced_by_cs(driver_priv->bo, info->cs)) {
flush = TRUE;
diff --git a/src/radeon_kms.c b/src/radeon_kms.c
index f4c54b30..59f82818 100644
--- a/src/radeon_kms.c
+++ b/src/radeon_kms.c
@@ -70,6 +70,8 @@ const OptionInfoRec RADEONOptions_KMS[] = {
{ OPTION_EXA_VSYNC, "EXAVSync", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_EXA_PIXMAPS, "EXAPixmaps", OPTV_BOOLEAN, {0}, FALSE },
{ OPTION_ZAPHOD_HEADS, "ZaphodHeads", OPTV_STRING, {0}, FALSE },
+ { OPTION_PAGE_FLIP, "EnablePageFlip", OPTV_BOOLEAN, {0}, FALSE },
+ { OPTION_SWAPBUFFERS_WAIT,"SwapbuffersWait", OPTV_BOOLEAN, {0}, FALSE },
{ -1, NULL, OPTV_NONE, {0}, FALSE }
};
@@ -620,6 +622,18 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
xf86DrvMsg(pScrn->scrnIndex, X_INFO,
"KMS Color Tiling: %sabled\n", info->allowColorTiling ? "en" : "dis");
+ if (info->dri->pKernelDRMVersion->version_minor >= 8) {
+ info->allowPageFlip = xf86ReturnOptValBool(info->Options,
+ OPTION_PAGE_FLIP, TRUE);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "KMS Pageflipping: %sabled\n", info->allowPageFlip ? "en" : "dis");
+ }
+
+ info->swapBuffersWait = xf86ReturnOptValBool(info->Options,
+ OPTION_SWAPBUFFERS_WAIT, TRUE);
+ xf86DrvMsg(pScrn->scrnIndex, X_INFO,
+ "SwapBuffers wait for vsync: %sabled\n", info->swapBuffersWait ? "en" : "dis");
+
if (drmmode_pre_init(pScrn, &info->drmmode, pScrn->bitsPerPixel / 8) == FALSE) {
xf86DrvMsg(pScrn->scrnIndex, X_ERROR, "Kernel modesetting setup failed\n");
goto fail;
@@ -678,7 +692,9 @@ Bool RADEONPreInit_KMS(ScrnInfoPtr pScrn, int flags)
/* no tiled scanout on r6xx+ yet */
if (info->allowColorTiling) {
- if (info->ChipFamily < CHIP_FAMILY_R600)
+ if (info->ChipFamily >= CHIP_FAMILY_R600)
+ tiling |= RADEON_TILING_MICRO;
+ else
tiling |= RADEON_TILING_MACRO;
}
cpp = pScrn->bitsPerPixel / 8;
@@ -1115,9 +1131,10 @@ static Bool radeon_setup_kernel_mem(ScreenPtr pScreen)
return FALSE;
}
- /* no tiled scanout on r6xx+ yet */
if (info->allowColorTiling) {
- if (info->ChipFamily < CHIP_FAMILY_R600)
+ if (info->ChipFamily >= CHIP_FAMILY_R600)
+ tiling_flags |= RADEON_TILING_MICRO;
+ else
tiling_flags |= RADEON_TILING_MACRO;
}
pitch = RADEON_ALIGN(pScrn->displayWidth, drmmode_get_pitch_align(pScrn, cpp, tiling_flags)) * cpp;