From: Jesse Barnes <jbar...@virtuousgeek.org>

Sits on top of KMS page flipping ioctl.
---

Userspace side of the async pageflip ioctl plus a test case
added to modetest.c


 libdrm/xf86drmMode.c      |   13 ++++
 libdrm/xf86drmMode.h      |    4 +-
 shared-core/drm.h         |   26 ++++++++-
 shared-core/drm_mode.h    |   16 +++++
 tests/modetest/modetest.c |  137 ++++++++++++++++++++++++++++++++++++++++++--
 5 files changed, 185 insertions(+), 11 deletions(-)

diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
index ea11207..80ac57d 100644
--- a/libdrm/xf86drmMode.c
+++ b/libdrm/xf86drmMode.c
@@ -664,3 +664,16 @@ int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t 
size,
 
        return 0;
 }
+
+int drmModePageFlip(int fd, uint32_t crtc_id,
+                   uint32_t fb_id, void *user_data)
+{
+       struct drm_mode_page_flip flip;
+
+       flip.fb_id = fb_id;
+       flip.crtc_id = crtc_id;
+       flip.user_data = VOID2U64(user_data);
+       flip.flags = 0;
+
+       return drmIoctl(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
+}
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
index 62304bb..730184e 100644
--- a/libdrm/xf86drmMode.h
+++ b/libdrm/xf86drmMode.h
@@ -259,8 +259,6 @@ typedef struct _drmModeConnector {
        uint32_t *encoders; /**< List of encoder ids */
 } drmModeConnector, *drmModeConnectorPtr;
 
-
-
 extern void drmModeFreeModeInfo( drmModeModeInfoPtr ptr );
 extern void drmModeFreeResources( drmModeResPtr ptr );
 extern void drmModeFreeFB( drmModeFBPtr ptr );
@@ -357,8 +355,8 @@ extern void drmModeFreePropertyBlob(drmModePropertyBlobPtr 
ptr);
 extern int drmModeConnectorSetProperty(int fd, uint32_t connector_id, uint32_t 
property_id,
                                    uint64_t value);
 extern int drmCheckModesettingSupported(const char *busid);
-
 extern int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
                               uint16_t *red, uint16_t *green, uint16_t *blue);
 extern int drmModeCrtcGetGamma(int fd, uint32_t crtc_id, uint32_t size,
                               uint16_t *red, uint16_t *green, uint16_t *blue);
+extern int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, void 
*user_data);
diff --git a/shared-core/drm.h b/shared-core/drm.h
index b97ba09..b01fc43 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -1107,7 +1107,7 @@ struct drm_gem_open {
 #define DRM_IOCTL_MODE_GETFB           DRM_IOWR(0xAD, struct drm_mode_fb_cmd)
 #define DRM_IOCTL_MODE_ADDFB           DRM_IOWR(0xAE, struct drm_mode_fb_cmd)
 #define DRM_IOCTL_MODE_RMFB            DRM_IOWR(0xAF, uint32_t)
-#define DRM_IOCTL_MODE_REPLACEFB       DRM_IOWR(0xB0, struct drm_mode_fb_cmd)
+#define DRM_IOCTL_MODE_PAGE_FLIP       DRM_IOW( 0xB0, struct 
drm_mode_page_flip)
 
 /*...@}*/
 
@@ -1122,6 +1122,30 @@ struct drm_gem_open {
 #define DRM_COMMAND_BASE                0x40
 #define DRM_COMMAND_END                 0xA0
 
+/**
+ * Header for events written back to userspace on the drm fd.  The
+ * type defines the type of event, the length specifies the total
+ * length of the event (including the header), and user_data is
+ * typically a 64 bit value passed with the ioctl that triggered the
+ * event.  A read on the drm fd will always only return complete
+ * events, that is, if for example the read buffer is 100 bytes, and
+ * there are two 64 byte events pending, only one will be returned.
+ */
+struct drm_event {
+       uint32_t type;
+       uint32_t length;
+       uint64_t user_data;
+};
+
+#define DRM_EVENT_MODE_PAGE_FLIP 0x01
+
+struct drm_event_page_flip {
+       struct drm_event base;
+       uint32_t tv_sec;
+       uint32_t tv_usec;
+       uint32_t frame;
+};
+
 /* typedef area */
 #ifndef __KERNEL__
 typedef struct drm_clip_rect drm_clip_rect_t;
diff --git a/shared-core/drm_mode.h b/shared-core/drm_mode.h
index 9b92733..bebe4e7 100644
--- a/shared-core/drm_mode.h
+++ b/shared-core/drm_mode.h
@@ -270,4 +270,20 @@ struct drm_mode_crtc_lut {
        uint64_t blue;
 };
 
+#define DRM_MODE_PAGE_FLIP_WAIT                (1<<0) /* block on previous 
page flip */
+#define DRM_MODE_PAGE_FLIP_FLAGS_MASK  (DRM_MODE_PAGE_FLIP_WAIT)
+
+struct drm_mode_page_flip {
+       /** Handle of new front buffer */
+       uint32_t fb_id;
+       uint32_t crtc_id;
+
+       /* 64 bit cookie returned to userspace in the page flip event. */
+       uint64_t user_data;
+       /**
+        * page flip flags (wait on flip only for now)
+        */
+       uint32_t flags;
+};
+
 #endif
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 58e0e4c..6eed564 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -46,6 +46,7 @@
 #include <unistd.h>
 #include <string.h>
 #include <errno.h>
+#include <sys/poll.h>
 
 #include "xf86drm.h"
 #include "xf86drmMode.h"
@@ -271,6 +272,9 @@ struct connector {
        drmModeModeInfo *mode;
        drmModeEncoder *encoder;
        int crtc;
+       unsigned int fb_id;
+       struct timeval start;
+       int swap_count;
 };     
 
 static void
@@ -447,7 +451,7 @@ create_test_buffer(drm_intel_bufmgr *bufmgr,
                d = div(i, width);
                fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 
6);
        }
-       drm_intel_bo_unmap(bo);
+       drm_intel_gem_bo_unmap(bo);
 
        *bo_out = bo;
        *stride_out = stride;
@@ -457,15 +461,51 @@ create_test_buffer(drm_intel_bufmgr *bufmgr,
 
 #endif
 
+static int
+create_black_buffer(drm_intel_bufmgr *bufmgr,
+                   int width, int height, int *stride_out, drm_intel_bo 
**bo_out)
+{
+       drm_intel_bo *bo;
+       unsigned int *fb_ptr;
+       int size, ret, i, stride;
+       div_t d;
+
+       /* Mode size at 32 bpp */
+       stride = width * 4;
+       size = stride * height;
+
+       bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096);
+       if (!bo) {
+               fprintf(stderr, "failed to alloc buffer: %s\n",
+                       strerror(errno));
+               return -1;
+       }
+
+       ret = drm_intel_gem_bo_map_gtt(bo);
+       if (ret) {
+               fprintf(stderr, "failed to GTT map buffer: %s\n",
+                       strerror(errno));
+               return -1;
+       }
+
+       memset(bo->virtual, 0, size);
+       drm_intel_gem_bo_unmap_gtt(bo);
+
+       *bo_out = bo;
+       *stride_out = stride;
+
+       return 0;
+}
+
 static void
-set_mode(struct connector *c, int count)
+set_mode(struct connector *c, int count, int page_flip)
 {
        drmModeConnector *connector;
        drmModeEncoder *encoder = NULL;
        struct drm_mode_modeinfo *mode = NULL;
        drm_intel_bufmgr *bufmgr;
-       drm_intel_bo *bo;
-       unsigned int fb_id;
+       drm_intel_bo *bo, *other_bo;
+       unsigned int fb_id, other_fb_id;
        int i, j, ret, width, height, x, stride;
 
        width = 0;
@@ -497,7 +537,6 @@ set_mode(struct connector *c, int count)
 
        x = 0;
        for (i = 0; i < count; i++) {
-               int crtc_id;
                if (c[i].mode == NULL)
                        continue;
 
@@ -507,17 +546,96 @@ set_mode(struct connector *c, int count)
                ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0,
                                     &c[i].id, 1, c[i].mode);
                x += c[i].mode->hdisplay;
+               c[i].fb_id = fb_id;
 
                if (ret) {
                        fprintf(stderr, "failed to set mode: %s\n", 
strerror(errno));
                        return;
                }
        }
+
+       if (!page_flip)
+               return;
+
+       if (create_black_buffer(bufmgr, width, height, &stride, &other_bo))
+               return;
+
+       ret = drmModeAddFB(fd, width, height, 32, 32, stride, other_bo->handle,
+                          &other_fb_id);
+       if (ret) {
+               fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
+               return;
+       }
+
+       for (i = 0; i < count; i++) {
+               if (c[i].mode == NULL)
+                       continue;
+
+               drmModePageFlip(fd, c[i].crtc, other_fb_id, &c[i]);
+               gettimeofday(&c[i].start, NULL);
+               c[i].swap_count = 0;
+       }
+
+       while (1) {
+               struct connector *c;
+               unsigned int new_fb_id;
+               int len, ms;
+               struct drm_event_page_flip event;
+               struct pollfd pfd[2];
+
+               pfd[0].fd = 0;
+               pfd[0].events = POLLIN;
+               pfd[1].fd = fd;
+               pfd[1].events = POLLIN;
+
+               if (poll(pfd, 2, -1) < 0) {
+                       fprintf(stderr, "poll error\n");
+                       break;
+               }
+
+               if (pfd[0].revents)
+                       break;
+
+               len = read(fd, &event, sizeof event);
+
+               if (len < sizeof event)
+                       break;
+               if (event.base.type != DRM_EVENT_MODE_PAGE_FLIP) {
+                       fprintf(stderr,
+                               "got unhandled event %d\n", event.base.type);
+                       continue;
+               }
+
+               fprintf(stderr, "flip done, frame %d, time %d.%03d\n",
+                       event.frame, event.tv_sec % 100,
+                       event.tv_usec / 1000);
+
+               c = (struct connector *) (long) event.base.user_data;
+               if (c->fb_id == fb_id)
+                       new_fb_id = other_fb_id;
+               else
+                       new_fb_id = fb_id;
+                       
+               drmModePageFlip(fd, c->crtc, new_fb_id, c);
+               c->fb_id = new_fb_id;
+               c->swap_count++;
+               if (c->swap_count == 60) {
+                       struct timeval end;
+                       double t;
+
+                       gettimeofday(&end, NULL);
+                       t = end.tv_sec + end.tv_usec * 1e-6 -
+                               (c->start.tv_sec + c->start.tv_usec * 1e-6);
+                       fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t);
+                       c->swap_count = 0;
+                       c->start = end;
+               }
+       }
 }
 
 extern char *optarg;
 extern int optind, opterr, optopt;
-static char optstr[] = "ecpmfs:";
+static char optstr[] = "ecpmfs:v";
 
 void usage(char *name)
 {
@@ -527,6 +645,7 @@ void usage(char *name)
        fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n");
        fprintf(stderr, "\t-m\tlist modes\n");
        fprintf(stderr, "\t-f\tlist framebuffers\n");
+       fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
        fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n");
        fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n");
        fprintf(stderr, "\n\tDefault is to dump all info.\n");
@@ -539,6 +658,7 @@ int main(int argc, char **argv)
 {
        int c;
        int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0;
+       int test_vsync = 0;
        char *modules[] = { "i915", "radeon" };
        char *modeset = NULL, *mode, *connector;
        int i, connector_id, count = 0;
@@ -562,6 +682,9 @@ int main(int argc, char **argv)
                case 'f':
                        framebuffers = 1;
                        break;
+               case 'v':
+                       test_vsync = 1;
+                       break;
                case 's':
                        modeset = strdup(optarg);
                        con_args[count].crtc = -1;
@@ -614,7 +737,7 @@ int main(int argc, char **argv)
        dump_resource(framebuffers);
 
        if (count > 0) {
-               set_mode(con_args, count);
+               set_mode(con_args, count, test_vsync);
                getchar();
        }
 
-- 
1.6.2


------------------------------------------------------------------------------
The NEW KODAK i700 Series Scanners deliver under ANY circumstances! Your
production scanning environment may not be a perfect world - but thanks to
Kodak, there's a perfect scanner to get the job done! With the NEW KODAK i700
Series Scanner you'll get full speed at 300 dpi even with all image 
processing features enabled. http://p.sf.net/sfu/kodak-com
--
_______________________________________________
Dri-devel mailing list
Dri-devel@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/dri-devel

Reply via email to