diff options
author | Jesse Barnes <jbarnes@virtuousgeek.org> | 2009-05-01 14:52:26 -0700 |
---|---|---|
committer | Kristian Høgsberg <krh@redhat.com> | 2009-07-31 06:55:16 -0400 |
commit | 6c46edc14f49210465cef0467bad00b7fefd5161 (patch) | |
tree | c6de65b5dc0fa0fdbaf5eb68aa4de4d6b3027ed7 | |
parent | 50e2a6734de43a135aa91cd6e6fb5147e15ce315 (diff) |
Add support for DRI2 SwapBuffers request
Support the new DRI2 SwapBuffers request with a KMS-specific page flip ioctl.
Doesn't help prevent tearing from CopyRegion requests, but full buffer swaps
look nice.
There's still an open issue with buffer resize in here somewhere; maybe
pI830->front_buffer isn't getting fully fixed up at swap time?
-rw-r--r-- | src/drmmode_display.c | 101 | ||||
-rw-r--r-- | src/i830.h | 6 | ||||
-rw-r--r-- | src/i830_dri.c | 78 | ||||
-rw-r--r-- | src/i830_dri.h | 6 |
4 files changed, 185 insertions, 6 deletions
diff --git a/src/drmmode_display.c b/src/drmmode_display.c index 814743b3..e590a2f7 100644 --- a/src/drmmode_display.c +++ b/src/drmmode_display.c @@ -30,6 +30,7 @@ #endif #include <errno.h> +#include <poll.h> #include "xorgVersion.h" @@ -343,6 +344,7 @@ static PixmapPtr drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) { ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; unsigned long rotate_pitch; @@ -375,12 +377,16 @@ drmmode_crtc_shadow_create(xf86CrtcPtr crtc, void *data, int width, int height) if (drmmode_crtc->rotate_bo) i830_set_pixmap_bo(rotate_pixmap, drmmode_crtc->rotate_bo); + pI830->shadow_present = TRUE; + return rotate_pixmap; } static void drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *data) { + ScrnInfoPtr pScrn = crtc->scrn; + I830Ptr pI830 = I830PTR(pScrn); drmmode_crtc_private_ptr drmmode_crtc = crtc->driver_private; drmmode_ptr drmmode = drmmode_crtc->drmmode; @@ -398,6 +404,7 @@ drmmode_crtc_shadow_destroy(xf86CrtcPtr crtc, PixmapPtr rotate_pixmap, void *dat dri_bo_unreference(drmmode_crtc->rotate_bo); drmmode_crtc->rotate_bo = NULL; } + pI830->shadow_present = FALSE; } static void @@ -1085,6 +1092,88 @@ drmmode_xf86crtc_resize (ScrnInfoPtr scrn, int width, int height) return FALSE; } +Bool +drmmode_do_pageflip(DrawablePtr pDraw, dri_bo *new_front, dri_bo *old_front) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + xf86CrtcConfigPtr config = XF86_CRTC_CONFIG_PTR(pScrn); + drmmode_crtc_private_ptr drmmode_crtc = config->crtc[0]->driver_private; + drmmode_ptr drmmode = drmmode_crtc->drmmode; + unsigned int pitch = pScrn->displayWidth * pI830->cpp; + int i, old_fb_id; + unsigned int crtc_id; + struct pollfd drmpoll; + drmEventContext handler = { .page_flip_handler = NULL }; + + /* + * Create a new handle for the back buffer + */ + old_fb_id = drmmode->fb_id; + if (drmModeAddFB(drmmode->fd, pScrn->virtualX, pScrn->virtualY, + pScrn->depth, pScrn->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. + */ + for (i = 0; i < config->num_crtc; i++) { + xf86CrtcPtr crtc = config->crtc[i]; + + if (!crtc->enabled) + continue; + + drmmode_crtc = crtc->driver_private; + crtc_id = drmmode_crtc->mode_crtc->crtc_id; + if (drmModePageFlip(drmmode->fd, crtc_id, drmmode->fb_id, NULL)) { + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, + "flip queue failed: %s\n", strerror(errno)); + goto error_undo; + } + } + +retry: + drmpoll.fd = drmmode->fd; + drmpoll.events = POLLIN; + if (poll(&drmpoll, 1, -1) < 0) { + if (errno == EINTR) + goto retry; + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "poll failed: %s\n", + strerror(errno)); + goto error_undo; + } + + drmHandleEvent(drmmode->fd, &handler); + + dri_bo_pin(new_front, 0); + dri_bo_unpin(new_front); + + pScrn->fbOffset = new_front->offset; + pI830->front_buffer->bo = new_front; + pI830->front_buffer->offset = new_front->offset; + + drmModeRmFB(drmmode->fd, old_fb_id); + + return TRUE; + +error_undo: + drmModeRmFB(drmmode->fd, drmmode->fb_id); + drmmode->fb_id = old_fb_id; + +error_out: + xf86DrvMsg(pScrn->scrnIndex, X_WARNING, "Page flip failed: %s\n", + strerror(errno)); + return FALSE; +} + static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { drmmode_xf86crtc_resize }; @@ -1092,8 +1181,10 @@ static const xf86CrtcConfigFuncsRec drmmode_xf86crtc_config_funcs = { Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) { xf86CrtcConfigPtr xf86_config; + I830Ptr pI830 = I830PTR(pScrn); drmmode_ptr drmmode; - int i; + unsigned int i, bad_crtc = 0; + int ret; drmmode = xnfalloc(sizeof *drmmode); drmmode->fd = fd; @@ -1120,6 +1211,14 @@ Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp) xf86InitialConfiguration(pScrn, TRUE); + /* Check for swapbuffers support */ + ret = drmModePageFlip(drmmode->fd, bad_crtc, 1, NULL); + if (ret < 0 && errno == ENOENT) { /* bad CRTC or FB number */ + xf86DrvMsg(pScrn->scrnIndex, X_INFO, + "Kernel page flipping support detected, enabling\n"); + pI830->use_swap_buffers = TRUE; + } + return TRUE; } @@ -65,6 +65,7 @@ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include "sarea.h" #define _XF86DRI_SERVER_ #include "dri.h" +#include "dri2.h" #include "GL/glxint.h" #include "i830_dri.h" #include "intel_bufmgr.h" @@ -395,6 +396,7 @@ typedef struct _I830Rec { #endif XF86ModReqInfo shadowReq; /* to test for later libshadow */ + Bool shadow_present; Rotation rotation; void (*PointerMoved)(int, int, int); CreateScreenResourcesProcPtr CreateScreenResources; @@ -496,6 +498,8 @@ typedef struct _I830Rec { int drmSubFD; char deviceName[64]; + Bool use_swap_buffers; + /* Broken-out options. */ OptionInfoPtr Options; @@ -691,6 +695,8 @@ void I830DRI2CloseScreen(ScreenPtr pScreen); extern Bool drmmode_pre_init(ScrnInfoPtr pScrn, int fd, int cpp); extern int drmmode_get_pipe_from_crtc_id(drm_intel_bufmgr *bufmgr, xf86CrtcPtr crtc); extern int drmmode_output_dpms_status(xf86OutputPtr output); +extern Bool drmmode_do_pageflip(DrawablePtr pDraw, dri_bo *new_front, + dri_bo *old_front); extern Bool i830_crtc_on(xf86CrtcPtr crtc); extern int i830_crtc_to_pipe(xf86CrtcPtr crtc); diff --git a/src/i830_dri.c b/src/i830_dri.c index 40d11e4c..0f38d097 100644 --- a/src/i830_dri.c +++ b/src/i830_dri.c @@ -45,6 +45,8 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. #include <errno.h> #include <unistd.h> #include <fcntl.h> +#include <sys/time.h> +#include <time.h> #include "xf86.h" #include "xf86_OSproc.h" @@ -73,11 +75,6 @@ USE OR OTHER DEALINGS IN THE SOFTWARE. extern XF86ModuleData dri2ModuleData; #endif -typedef struct { - PixmapPtr pPixmap; - unsigned int attachment; -} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; - #ifndef USE_DRI2_1_1_0 static DRI2BufferPtr I830DRI2CreateBuffers(DrawablePtr pDraw, unsigned int *attachments, int count) @@ -359,6 +356,70 @@ I830DRI2CopyRegion(DrawablePtr pDraw, RegionPtr pRegion, } +#if DRI2INFOREC_VERSION >= 4 +/* Check various flip constraints (drawable parameters vs screen params) */ +static Bool +i830_flip_ok(DrawablePtr pDraw) +{ + ScreenPtr pScreen = pDraw->pScreen; + ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; + I830Ptr pI830 = I830PTR(pScrn); + + if (pI830->shadow_present) + return FALSE; + if (pDraw->width != pScrn->virtualX) + return FALSE; + if (pDraw->height != pScrn->virtualY) + return FALSE; + if (pDraw->depth != pScrn->depth) + return FALSE; + + return TRUE; +} + +/* + * DRI2SwapBuffers should try to do a buffer swap if possible, however: + * - if we're swapping buffers smaller than the screen, we have to blit + * - if the back buffer doesn't match the screen depth, we have to blit + * - otherwise we try to swap, and return to the caller the new front + * and back buffers + */ +static Bool +I830DRI2SwapBuffers(DrawablePtr pDraw, DRI2BufferPtr front, DRI2BufferPtr back) +{ + ScreenPtr pScreen = pDraw->pScreen; + I830DRI2BufferPrivatePtr front_priv, back_priv; + dri_bo *tmp_bo; + int tmp; + + front_priv = front->driverPrivate; + back_priv = back->driverPrivate; + + if (!i830_flip_ok(pDraw)) + return FALSE; + + /* Swap BO names so DRI works */ + tmp = front->name; + front->name = back->name; + back->name = tmp; + + /* Swap pixmap bos */ + dri_bo_reference(i830_get_pixmap_bo(front_priv->pPixmap)); + + tmp_bo = i830_get_pixmap_bo(front_priv->pPixmap); + i830_set_pixmap_bo(front_priv->pPixmap, + i830_get_pixmap_bo(back_priv->pPixmap)); + i830_set_pixmap_bo(back_priv->pPixmap, tmp_bo); /* should be screen */ + + if (front_priv->pPixmap != pScreen->GetScreenPixmap(pScreen)) + FatalError("swapbuffers with bad front\n"); + + /* Page flip the full screen buffer */ + return drmmode_do_pageflip(pDraw, i830_get_pixmap_bo(front_priv->pPixmap), + i830_get_pixmap_bo(back_priv->pPixmap)); +} +#endif + Bool I830DRI2ScreenInit(ScreenPtr pScreen) { ScrnInfoPtr pScrn = xf86Screens[pScreen->myNum]; @@ -428,6 +489,13 @@ Bool I830DRI2ScreenInit(ScreenPtr pScreen) # endif #endif +#if DRI2INFOREC_VERSION >= 4 + if (pI830->use_swap_buffers) { + info.version = 4; + info.SwapBuffers = I830DRI2SwapBuffers; + } +#endif + info.CopyRegion = I830DRI2CopyRegion; return DRI2ScreenInit(pScreen, &info); diff --git a/src/i830_dri.h b/src/i830_dri.h index bedbcbe2..e35e9402 100644 --- a/src/i830_dri.h +++ b/src/i830_dri.h @@ -2,6 +2,7 @@ #ifndef _I830_DRI_H #define _I830_DRI_H +#include "xorg-server.h" #include "xf86drm.h" #include "i830_common.h" @@ -58,4 +59,9 @@ typedef struct { int dummy; } I830DRIContextRec, *I830DRIContextPtr; +typedef struct { + PixmapPtr pPixmap; + unsigned int attachment; +} I830DRI2BufferPrivateRec, *I830DRI2BufferPrivatePtr; + #endif |