diff options
author | Francisco Jerez <currojerez@riseup.net> | 2010-10-21 22:57:08 +0200 |
---|---|---|
committer | Francisco Jerez <currojerez@riseup.net> | 2010-10-22 15:33:07 +0200 |
commit | eb83c830c87bce345748edef3b50660246143db7 (patch) | |
tree | 3638e9958c2384b93018ddb659b9c1543be4ea3f | |
parent | c88f13e25b0040c1dd0f93e0ac40f62a6005ce59 (diff) | |
download | xorg-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.c | 40 | ||||
-rw-r--r-- | src/nouveau_dri2.c | 52 | ||||
-rw-r--r-- | src/nouveau_local.h | 6 | ||||
-rw-r--r-- | src/nv_driver.c | 11 | ||||
-rw-r--r-- | src/nv_proto.h | 1 | ||||
-rw-r--r-- | src/nv_type.h | 1 |
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(®ion, &box, 0); - nouveau_dri2_copy_region(draw, ®ion, 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(®ion, &box, 0); + + type = DRI2_BLIT_COMPLETE; + nouveau_dri2_copy_region(draw, ®ion, 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; |