summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDamien Lespiau <damien.lespiau@intel.com>2012-09-10 13:33:26 +0100
committerDamien Lespiau <damien.lespiau@intel.com>2013-09-06 20:02:07 +0100
commit3d02fdd75d6f77f518d8bead99ddd429a25000ed (patch)
tree79285321b83348bb994605f620a8c5073403b276
parent57bea2997f273c6a15d6b3a138084af071295856 (diff)
testdisplay: Test the stereo 3D modes20130906-stereo-3d
Now that modes have flags to describe which 3d formats the sink supports, it's time to test them. The new test cycles through the supported 3D formats and paint 3D stereoscopic images taken from publicly available samples: http://www.quantumdata.com/apps/3D/sample_BMP.asp Signed-off-by: Damien Lespiau <damien.lespiau@intel.com>
-rw-r--r--tests/testdisplay.c255
1 files changed, 252 insertions, 3 deletions
diff --git a/tests/testdisplay.c b/tests/testdisplay.c
index df3b4d4..a8b39fe 100644
--- a/tests/testdisplay.c
+++ b/tests/testdisplay.c
@@ -54,10 +54,13 @@
#include <math.h>
#include <stdint.h>
#include <stdbool.h>
+#include <strings.h>
#include <unistd.h>
#include <sys/poll.h>
#include <sys/time.h>
#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "i915_drm.h"
#include "drmtest.h"
@@ -69,7 +72,7 @@
drmModeRes *resources;
int drm_fd, modes;
int test_all_modes = 0, test_preferred_mode = 0, force_mode = 0, test_plane,
- enable_tiling;
+ test_3d_modes, enable_tiling;
int sleep_between_modes = 5;
uint32_t depth = 24, stride, bpp;
int qr_code = 0;
@@ -362,6 +365,9 @@ set_mode(struct connector *c)
if (test_all_modes)
c->mode = c->connector->modes[j];
+ /* set_mode() only tests 2D modes */
+ c->mode.flags &= ~DRMTEST_MODE_FLAG_3D_MASK;
+
if (!c->mode_valid)
continue;
@@ -404,6 +410,223 @@ set_mode(struct connector *c)
drmModeFreeConnector(c->connector);
}
+static void adjust_3d_timings(drmModeModeInfo *mode, unsigned int format)
+{
+ uint16_t vdisplay, vactive_space;
+
+ /* just set the 3D format we are setting (this is not used by the
+ * kernel, it's just for kmstest_dump_mode()) */
+ mode->flags &= ~DRMTEST_MODE_FLAG_3D_MASK;
+ mode->flags |= format;
+
+ switch (format) {
+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+ return;
+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
+ vactive_space = mode->vtotal - mode->vdisplay;
+ vdisplay = mode->vdisplay;
+
+ mode->vdisplay += vdisplay + vactive_space;
+ mode->vsync_start += vdisplay + vactive_space;
+ mode->vsync_end += vdisplay + vactive_space;
+ mode->vtotal += vdisplay + vactive_space;
+ mode->clock = (mode->vtotal * mode->htotal * mode->vrefresh) /
+ 1000;
+ return;
+ default:
+ assert(0);
+ }
+}
+
+struct box {
+ int x, y, width, height;
+};
+
+struct s3d_fb_layout {
+ int fb_width, fb_height;
+ struct box left, right;
+};
+
+static void box_init(struct box *box, int x, int y, int bwidth, int bheight)
+{
+ box->x = x;
+ box->y = y;
+ box->width = bwidth;
+ box->height = bheight;
+}
+
+static void box_print(const char * prefix, struct box *box)
+{
+ printf("%s: %d, %d, %d, %d\n", prefix,
+ box->x, box->y, box->width, box->height);
+}
+
+static void s3d_fb_layout_from_mode(struct s3d_fb_layout *layout,
+ drmModeModeInfo *mode)
+{
+ unsigned int format = mode->flags & DRMTEST_MODE_FLAG_3D_MASK;
+ const int hdisplay = mode->hdisplay, vdisplay = mode->vdisplay;
+ int middle;
+
+ switch (format) {
+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+ layout->fb_width = hdisplay;
+ layout->fb_height = vdisplay;
+
+ middle = vdisplay / 2;
+ box_init(&layout->left, 0, 0, hdisplay, middle);
+ box_init(&layout->right,
+ 0, middle, hdisplay, vdisplay - middle);
+ break;
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+ layout->fb_width = hdisplay;
+ layout->fb_height = vdisplay;
+
+ middle = hdisplay / 2;
+ box_init(&layout->left, 0, 0, middle, vdisplay);
+ box_init(&layout->right,
+ middle, 0, hdisplay - middle, vdisplay);
+ break;
+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
+ {
+ int vactive_space = mode->vtotal - vdisplay;
+
+ layout->fb_width = hdisplay;
+ layout->fb_height = 2 * vdisplay + vactive_space;
+
+ box_init(&layout->left,
+ 0, 0, hdisplay, vdisplay);
+ box_init(&layout->right,
+ 0, vdisplay + vactive_space, hdisplay, vdisplay);
+ break;
+ }
+ default:
+ assert(0);
+ }
+}
+
+static const char *s3d_mode_str(unsigned format)
+{
+ switch (format) {
+ case DRM_MODE_FLAG_3D_TOP_AND_BOTTOM:
+ return "TB";
+ case DRM_MODE_FLAG_3D_SIDE_BY_SIDE_HALF:
+ return "SbSH";
+ case DRM_MODE_FLAG_3D_FRAME_PACKING:
+ return "FP";
+ default:
+ assert(0);
+ }
+}
+
+static uint32_t create_s3d_fb(drmModeModeInfo *mode, struct kmstest_fb *fb)
+{
+ struct s3d_fb_layout layout;
+ cairo_t *cr;
+ uint32_t fb_id;
+
+ s3d_fb_layout_from_mode(&layout, mode);
+ box_print("left: ", &layout.left);
+ box_print("right: ", &layout.right);
+ fb_id = kmstest_create_fb(drm_fd, layout.fb_width, layout.fb_height,
+ bpp, depth, enable_tiling, fb);
+ cr = kmstest_get_cairo_ctx(drm_fd, fb);
+
+ kmstest_paint_image(cr, IGT_DATADIR"/1080p-left.png",
+ layout.left.x, layout.left.y,
+ layout.left.width, layout.left.height);
+ kmstest_paint_image(cr, IGT_DATADIR"/1080p-right.png",
+ layout.right.x, layout.right.y,
+ layout.right.width, layout.right.height);
+
+#if 0 /* Comment this out if you want to see what the composited fb looks
+ like */
+ {
+ char buffer[64];
+
+ snprintf(buffer, sizeof(buffer), "%dx%d@%dHz-%s.png",
+ mode->hdisplay,
+ mode->vdisplay,
+ mode->vrefresh,
+ s3d_mode_str(mode->flags & DRMTEST_MODE_FLAG_3D_MASK));
+
+ kmstest_write_fb(drm_fd, fb, buffer);
+ }
+#endif
+
+ return fb_id;
+}
+
+static void do_set_3d_format(struct connector *c, unsigned int format)
+{
+ uint32_t fb_id;
+ struct kmstest_fb fb_info;
+
+ fb_id = create_s3d_fb(&c->mode, &fb_info);
+ adjust_3d_timings(&c->mode, format);
+
+ if (drmModeSetCrtc(drm_fd, c->crtc, fb_id, 0, 0,
+ &c->id, 1, &c->mode)) {
+ fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n",
+ width, height, c->mode.vrefresh,
+ strerror(errno));
+ }
+}
+
+static void
+set_3d_mode(struct connector *c)
+{
+ int i;
+
+ for (i = 0; i < c->connector->count_modes; i++) {
+ unsigned int s3d_formats, format;
+
+ c->mode = c->connector->modes[i];
+
+ if (!c->mode_valid)
+ continue;
+
+ s3d_formats = c->mode.flags & DRMTEST_MODE_FLAG_3D_MASK;
+ if (!s3d_formats)
+ continue;
+
+ do {
+ format = 1 << (ffs(s3d_formats) - 1);
+
+ /*
+ * Modify the mode flags to specify which 3D format is
+ * being set.
+ *
+ * XXX: One would need to also clear the upper bits of
+ * flags in case extra modes/flags are added
+ */
+ c->mode.flags &= ~DRMTEST_MODE_FLAG_3D_MASK;
+ c->mode.flags |= format;
+
+ do_set_3d_format(c, format);
+
+ /*
+ * The mode may have been adjusted for this format,
+ * reset it to its origin timings
+ */
+ c->mode = c->connector->modes[i];
+
+ if (qr_code){
+ set_single();
+ pause();
+ } else if (sleep_between_modes)
+ sleep(sleep_between_modes);
+
+ s3d_formats &= ~format;
+ } while (s3d_formats);
+
+ }
+
+ drmModeFreeEncoder(c->encoder);
+ drmModeFreeConnector(c->connector);
+}
+
/*
* Re-probe outputs and light up as many as possible.
*
@@ -458,12 +681,29 @@ int update_display(void)
}
}
+ if (test_3d_modes) {
+ for (c = 0; c < resources->count_connectors; c++) {
+ struct connector *connector = &connectors[c];
+
+ connector->id = resources->connectors[c];
+
+ connector_find_preferred_mode(connector->id,
+ -1UL,
+ specified_mode_num,
+ connector);
+ if (!connector->mode_valid)
+ continue;
+
+ set_3d_mode(connector);
+ }
+ }
+
free(connectors);
drmModeFreeResources(resources);
return 1;
}
-static char optstr[] = "hiaf:s:d:p:mrto:";
+static char optstr[] = "3hiaf:s:d:p:mrto:";
static void __attribute__((noreturn)) usage(char *name)
{
@@ -474,6 +714,7 @@ static void __attribute__((noreturn)) usage(char *name)
fprintf(stderr, "\t-d\t<depth>\tbit depth of scanout buffer\n");
fprintf(stderr, "\t-p\t<planew,h>,<crtcx,y>,<crtcw,h> test overlay plane\n");
fprintf(stderr, "\t-m\ttest the preferred mode\n");
+ fprintf(stderr, "\t-3\ttest all 3D modes\n");
fprintf(stderr, "\t-t\tuse a tiled framebuffer\n");
fprintf(stderr, "\t-r\tprint a QR code on the screen whose content is \"pass\" for the automatic test\n");
fprintf(stderr, "\t-o\t<id of the display>,<number of the mode>\tonly test specified mode on the specified display\n");
@@ -536,6 +777,9 @@ int main(int argc, char **argv)
opterr = 0;
while ((c = getopt(argc, argv, optstr)) != -1) {
switch (c) {
+ case '3':
+ test_3d_modes = 1;
+ break;
case 'i':
opt_dump_info = true;
break;
@@ -594,11 +838,16 @@ int main(int argc, char **argv)
bpp = 32;
if (!test_all_modes && !force_mode && !test_preferred_mode &&
- specified_mode_num == -1)
+ specified_mode_num == -1 && !test_3d_modes)
test_all_modes = 1;
drm_fd = drm_open_any();
+ if (test_3d_modes && drmSetCap(drm_fd, DRM_CAP_STEREO_3D, 1) < 0) {
+ fprintf(stderr, "DRM_CAP_STEREO_3D isn't supported\n");
+ goto out_close;
+ }
+
if (opt_dump_info) {
dump_info();
goto out_close;