summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJesse Barnes <jbarnes@virtuousgeek.org>2009-05-01 14:52:26 -0700
committerKristian Høgsberg <krh@redhat.com>2009-07-31 06:55:16 -0400
commit6c46edc14f49210465cef0467bad00b7fefd5161 (patch)
treec6de65b5dc0fa0fdbaf5eb68aa4de4d6b3027ed7
parent50e2a6734de43a135aa91cd6e6fb5147e15ce315 (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.c101
-rw-r--r--src/i830.h6
-rw-r--r--src/i830_dri.c78
-rw-r--r--src/i830_dri.h6
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;
}
diff --git a/src/i830.h b/src/i830.h
index 58afe76a..d868c04e 100644
--- a/src/i830.h
+++ b/src/i830.h
@@ -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