summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisco Jerez <currojerez@riseup.net>2010-10-21 22:57:08 +0200
committerFrancisco Jerez <currojerez@riseup.net>2010-10-22 15:33:07 +0200
commiteb83c830c87bce345748edef3b50660246143db7 (patch)
tree3638e9958c2384b93018ddb659b9c1543be4ea3f
parentc88f13e25b0040c1dd0f93e0ac40f62a6005ce59 (diff)
downloadxorg-driver-xf86-video-nouveau-eb83c830c87bce345748edef3b50660246143db7.tar.gz
dri2: Add pageflip/exchange support.
Signed-off-by: Francisco Jerez <currojerez@riseup.net>
-rw-r--r--src/drmmode_display.c40
-rw-r--r--src/nouveau_dri2.c52
-rw-r--r--src/nouveau_local.h6
-rw-r--r--src/nv_driver.c11
-rw-r--r--src/nv_proto.h1
-rw-r--r--src/nv_type.h1
6 files changed, 104 insertions, 7 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c
index 4220cf5..94b19ea 100644
--- a/src/drmmode_display.c
+++ b/src/drmmode_display.c
@@ -1179,9 +1179,47 @@ drmmode_cursor_init(ScreenPtr pScreen)
return xf86_cursors_init(pScreen, size, size, flags);
}
-#ifdef HAVE_LIBUDEV
+Bool
+drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv)
+{
+ ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+ xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(scrn);
+ drmmode_crtc_private_ptr crtc = config->crtc[0]->driver_private;
+ drmmode_ptr mode = crtc->drmmode;
+ int ret, i, old_fb_id;
+
+ old_fb_id = mode->fb_id;
+ ret = drmModeAddFB(mode->fd, scrn->virtualX, scrn->virtualY,
+ scrn->depth, scrn->bitsPerPixel,
+ scrn->displayWidth * scrn->bitsPerPixel / 8,
+ nouveau_pixmap_bo(back)->handle, &mode->fb_id);
+ if (ret) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "add fb failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+
+ for (i = 0; i < config->num_crtc; i++) {
+ crtc = config->crtc[i]->driver_private;
+ if (!config->crtc[i]->enabled)
+ continue;
+ ret = drmModePageFlip(mode->fd, crtc->mode_crtc->crtc_id,
+ mode->fb_id, 0, priv);
+ if (ret) {
+ xf86DrvMsg(scrn->scrnIndex, X_WARNING,
+ "flip queue failed: %s\n", strerror(errno));
+ return FALSE;
+ }
+ }
+
+ drmModeRmFB(mode->fd, old_fb_id);
+
+ return TRUE;
+}
+
+#ifdef HAVE_LIBUDEV
static void
drmmode_handle_uevents(ScrnInfoPtr scrn)
{
diff --git a/src/nouveau_dri2.c b/src/nouveau_dri2.c
index 66fe16c..7fdfa9c 100644
--- a/src/nouveau_dri2.c
+++ b/src/nouveau_dri2.c
@@ -129,6 +129,20 @@ struct nouveau_dri2_vblank_state {
};
static Bool
+can_exchange(DrawablePtr draw, PixmapPtr dst_pix, PixmapPtr src_pix)
+{
+ ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
+ NVPtr pNv = NVPTR(scrn);
+
+ return (!nouveau_exa_pixmap_is_onscreen(dst_pix) ||
+ (DRI2CanFlip(draw) && pNv->has_pageflip)) &&
+ dst_pix->drawable.width == src_pix->drawable.width &&
+ dst_pix->drawable.height == src_pix->drawable.height &&
+ dst_pix->drawable.depth == src_pix->drawable.depth &&
+ dst_pix->devKind == src_pix->devKind;
+}
+
+static Bool
can_sync_to_vblank(DrawablePtr draw)
{
ScrnInfoPtr scrn = xf86Screens[draw->pScreen->myNum];
@@ -183,9 +197,7 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
struct nouveau_bo *dst_bo = nouveau_pixmap_bo(dst_pix);
struct nouveau_bo *src_bo = nouveau_pixmap_bo(src_pix);
struct nouveau_channel *chan = pNv->chan;
- BoxRec box = { 0, 0, draw->width, draw->height };
- RegionRec region;
- int ret;
+ int type, ret;
/* Throttle on the previous frame before swapping */
nouveau_bo_map(dst_bo, NOUVEAU_BO_RD);
@@ -209,12 +221,40 @@ nouveau_dri2_finish_swap(DrawablePtr draw, unsigned int frame,
FIRE_RING(chan);
}
+ if (can_exchange(draw, dst_pix, src_pix)) {
+ type = DRI2_EXCHANGE_COMPLETE;
- RegionInit(&region, &box, 0);
- nouveau_dri2_copy_region(draw, &region, s->dst, s->src);
+ if (DRI2CanFlip(draw)) {
+ type = DRI2_FLIP_COMPLETE;
+ ret = drmmode_page_flip(draw, src_pix, s);
+ if (!ret)
+ goto out;
+ }
+
+ SWAP(s->dst->name, s->src->name);
+ SWAP(nouveau_pixmap(dst_pix)->bo, nouveau_pixmap(src_pix)->bo);
+
+ } else {
+ BoxRec box = { 0, 0, draw->width, draw->height };
+ RegionRec region;
+
+ RegionInit(&region, &box, 0);
+
+ type = DRI2_BLIT_COMPLETE;
+ nouveau_dri2_copy_region(draw, &region, s->dst, s->src);
+ }
+ /*
+ * Tell the X server buffers are already swapped even if they're
+ * not, to prevent it from blocking the client on the next
+ * GetBuffers request (and let the client do triple-buffering).
+ *
+ * XXX - The DRI2SwapLimit() API will allow us to move this to
+ * the flip handler with no FPS hit.
+ */
DRI2SwapComplete(s->client, draw, frame, tv_sec, tv_usec,
- DRI2_BLIT_COMPLETE, s->func, s->data);
+ type, s->func, s->data);
+out:
free(s);
}
diff --git a/src/nouveau_local.h b/src/nouveau_local.h
index 5d3200a..38b861f 100644
--- a/src/nouveau_local.h
+++ b/src/nouveau_local.h
@@ -74,4 +74,10 @@ static inline int round_down_pow2(int x)
return 1 << log2i(x);
}
+#define SWAP(x, y) do { \
+ typeof(x) __z = (x); \
+ (x) = (y); \
+ (y) = __z; \
+ } while (0)
+
#endif
diff --git a/src/nv_driver.c b/src/nv_driver.c
index 5ef7984..fad7d6a 100644
--- a/src/nv_driver.c
+++ b/src/nv_driver.c
@@ -28,6 +28,7 @@
#include "xf86int10.h"
#include "xf86drm.h"
#include "xf86drmMode.h"
+#include "nouveau_drm.h"
/*
* Forward definitions for the functions that make up the driver.
@@ -586,6 +587,7 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
struct nouveau_device *dev;
NVPtr pNv;
MessageType from;
+ uint64_t v;
int ret, i;
if (flags & PROBE_DETECT) {
@@ -792,6 +794,15 @@ NVPreInit(ScrnInfoPtr pScrn, int flags)
pNv->glx_vblank ? "enabled" : "disabled");
}
+#ifdef NOUVEAU_GETPARAM_HAS_PAGEFLIP
+ ret = nouveau_device_get_param(pNv->dev,
+ NOUVEAU_GETPARAM_HAS_PAGEFLIP, &v);
+ if (!ret)
+ pNv->has_pageflip = v;
+#else
+ (void)v;
+#endif
+
if(xf86GetOptValInteger(pNv->Options, OPTION_VIDEO_KEY, &(pNv->videoKey))) {
xf86DrvMsg(pScrn->scrnIndex, X_CONFIG, "video key set to 0x%x\n",
pNv->videoKey);
diff --git a/src/nv_proto.h b/src/nv_proto.h
index ba234b3..8514af9 100644
--- a/src/nv_proto.h
+++ b/src/nv_proto.h
@@ -7,6 +7,7 @@ void drmmode_adjust_frame(ScrnInfoPtr pScrn, int x, int y, int flags);
void drmmode_remove_fb(ScrnInfoPtr pScrn);
Bool drmmode_cursor_init(ScreenPtr pScreen);
void drmmode_fbcon_copy(ScreenPtr pScreen);
+Bool drmmode_page_flip(DrawablePtr draw, PixmapPtr back, void *priv);
void drmmode_screen_init(ScreenPtr pScreen);
void drmmode_screen_fini(ScreenPtr pScreen);
diff --git a/src/nv_type.h b/src/nv_type.h
index a9c693f..94c385a 100644
--- a/src/nv_type.h
+++ b/src/nv_type.h
@@ -51,6 +51,7 @@ typedef struct _NVRec {
Bool wfb_enabled;
Bool tiled_scanout;
Bool glx_vblank;
+ Bool has_pageflip;
ScreenBlockHandlerProcPtr BlockHandler;
CreateScreenResourcesProcPtr CreateScreenResources;
CloseScreenProcPtr CloseScreen;