summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKristian Høgsberg <krh@bitplanet.net>2009-05-15 10:46:09 -0700
committerJesse Barnes <jbarnes@virtuousgeek.org>2009-05-15 10:46:09 -0700
commita6196a85cae417ef973d26693e130a0ec032b8d9 (patch)
tree1cb6bd0c21af2f1bca213d168f39c672106955d4
parentbd6f8f31cc94e2d9dcb1d4ee014893682868b834 (diff)
Update to new kernel page flip interface
And add modetest support for page flipping as a sanity check. [Note that the modetest flip isn't as pretty as glsync's orange smoothie.]
-rw-r--r--libdrm/xf86drmMode.c11
-rw-r--r--libdrm/xf86drmMode.h3
-rw-r--r--shared-core/drm.h26
-rw-r--r--shared-core/drm_mode.h15
-rw-r--r--tests/modetest/modetest.c137
5 files changed, 167 insertions, 25 deletions
diff --git a/libdrm/xf86drmMode.c b/libdrm/xf86drmMode.c
index ada56904..e8015e2d 100644
--- a/libdrm/xf86drmMode.c
+++ b/libdrm/xf86drmMode.c
@@ -665,15 +665,14 @@ int drmModeCrtcSetGamma(int fd, uint32_t crtc_id, uint32_t size,
return 0;
}
-int drmModePageFlip(int fd, uint32_t *crtc_ids, uint32_t crtc_count,
- uint32_t fb_id)
+int drmModePageFlip(int fd, uint32_t crtc_id, uint32_t fb_id, void *user_data)
{
- struct drm_gem_page_flip flip;
+ struct drm_mode_page_flip flip;
flip.fb_id = fb_id;
- flip.crtc_ids_ptr = (uint64_t)crtc_ids;
- flip.crtc_count = (uint32_t)crtc_count;
+ flip.crtc_id = crtc_id;
+ flip.user_data = VOID2U64(user_data);
flip.flags = 0;
- return drmIoctl(fd, DRM_IOCTL_GEM_PAGE_FLIP, &flip);
+ return drmIoctl(fd, DRM_IOCTL_MODE_PAGE_FLIP, &flip);
}
diff --git a/libdrm/xf86drmMode.h b/libdrm/xf86drmMode.h
index 2406e2fc..fe647073 100644
--- a/libdrm/xf86drmMode.h
+++ b/libdrm/xf86drmMode.h
@@ -360,5 +360,4 @@ 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_ids, uint32_t crtc_count,
- uint32_t fb_id);
+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 a677db89..3b4b242e 100644
--- a/shared-core/drm.h
+++ b/shared-core/drm.h
@@ -1113,7 +1113,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_GEM_PAGE_FLIP DRM_IOW( 0xB0, struct drm_gem_page_flip)
+#define DRM_IOCTL_MODE_PAGE_FLIP DRM_IOW( 0xB0, struct drm_mode_page_flip)
/*@}*/
@@ -1128,6 +1128,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 2354f775..bebe4e75 100644
--- a/shared-core/drm_mode.h
+++ b/shared-core/drm_mode.h
@@ -270,19 +270,16 @@ struct drm_mode_crtc_lut {
uint64_t blue;
};
-#define DRM_PAGE_FLIP_WAIT (1<<0) /* block on previous page flip */
-#define DRM_PAGE_FLIP_FLAGS_MASK (DRM_PAGE_FLIP_WAIT)
+#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_gem_page_flip {
+struct drm_mode_page_flip {
/** Handle of new front buffer */
uint32_t fb_id;
+ uint32_t crtc_id;
- /**
- * crtcs to flip
- */
- uint32_t crtc_count;
- uint64_t crtc_ids_ptr;
-
+ /* 64 bit cookie returned to userspace in the page flip event. */
+ uint64_t user_data;
/**
* page flip flags (wait on flip only for now)
*/
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index 58e0e4cf..6eed564e 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();
}