[PATCH 2/2] tests/testdisplay: Test the stereo 3D modes

Damien Lespiau damien.lespiau at gmail.com
Thu Sep 27 11:42:08 PDT 2012


From: Damien Lespiau <damien.lespiau at intel.com>

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 at intel.com>
---
 tests/testdisplay.c | 226 ++++++++++++++++++++++++++++++++++++++++++++++++++--
 1 file changed, 221 insertions(+), 5 deletions(-)

diff --git a/tests/testdisplay.c b/tests/testdisplay.c
index c52bb2f..e179c83 100644
--- a/tests/testdisplay.c
+++ b/tests/testdisplay.c
@@ -52,6 +52,7 @@
 #include <errno.h>
 #include <math.h>
 #include <stdint.h>
+#include <strings.h>
 #include <unistd.h>
 #include <sys/poll.h>
 #include <sys/time.h>
@@ -68,7 +69,7 @@
 drmModeRes *resources;
 int drm_fd, modes;
 int dump_info = 0, test_all_modes =0, test_preferred_mode = 0, force_mode = 0,
-	test_plane, enable_tiling;
+	test_plane, test_3d_modes, enable_tiling;
 int sleep_between_modes = 5;
 uint32_t depth = 24, stride, bpp;
 int qr_code = 0;
@@ -153,8 +154,51 @@ struct connector {
 	drmModeConnector *connector;
 	int crtc;
 	int pipe;
+
+	/* stereo 3d */
+	int s3d_format;
+	char s3d_image[32];
 };
 
+static bool connector_expose_3d(uint32_t connector_id, bool enable)
+{
+	drmModeConnector *connector;
+	drmModePropertyRes *property;
+	bool status = false;
+	int i;
+
+	connector = drmModeGetConnector(drm_fd, connector_id);
+	if (connector->count_props == 0)
+		return false;
+
+	for (i = 0; i < connector->count_props; i++) {
+		property = drmModeGetProperty(drm_fd, connector->props[i]);
+		if (!property)
+			continue;
+
+		if (strcmp(property->name, "expose 3D modes") == 0) {
+			if (drmModeConnectorSetProperty(drm_fd,
+							connector_id,
+							property->prop_id,
+							enable))
+				fprintf(stderr, "failed to set the \"expose 3D "
+					"modes\" property on connector %d: %s\n",
+					connector_id, strerror(errno));
+			else
+				status = true;
+			drmModeFreeProperty(property);
+			goto out;
+		}
+
+		drmModeFreeProperty(property);
+		property = NULL;
+	}
+
+out:
+	drmModeFreeConnector(connector);
+	return status;
+}
+
 static void dump_connectors_fd(int drmfd)
 {
 	int i, j;
@@ -172,11 +216,13 @@ static void dump_connectors_fd(int drmfd)
 	for (i = 0; i < mode_resources->count_connectors; i++) {
 		drmModeConnector *connector;
 
+		connector_expose_3d(mode_resources->connectors[i], TRUE);
+
 		connector = drmModeGetConnector(drmfd, mode_resources->connectors[i]);
 		if (!connector) {
 			fprintf(stderr, "could not get connector %i: %s\n",
 				mode_resources->connectors[i], strerror(errno));
-			continue;
+			goto next;
 		}
 
 		printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
@@ -188,7 +234,7 @@ static void dump_connectors_fd(int drmfd)
 		       connector->count_modes);
 
 		if (!connector->count_modes)
-			continue;
+			goto next;
 
 		printf("  modes:\n");
 		printf("  name refresh (Hz) hdisp hss hse htot vdisp "
@@ -197,6 +243,9 @@ static void dump_connectors_fd(int drmfd)
 			kmstest_dump_mode(&connector->modes[j]);
 
 		drmModeFreeConnector(connector);
+
+next:
+		connector_expose_3d(mode_resources->connectors[i], FALSE);
 	}
 	printf("\n");
 
@@ -554,6 +603,154 @@ set_mode(struct connector *c)
 	drmModeFreeConnector(c->connector);
 }
 
+static void
+paint_3d_image(cairo_t *cr, int l_width, int l_height, void *priv)
+{
+	struct connector *c = priv;
+	cairo_surface_t *image;
+
+	image = cairo_image_surface_create_from_png(c->s3d_image);
+
+	cairo_set_source_surface(cr, image, 0, 0);
+	cairo_paint(cr);
+
+	cairo_surface_destroy(image);
+}
+
+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 &= ~DRM_MODE_FLAG_3D_MASK;
+	mode->flags |= format;
+
+	switch (format) {
+	case DRM_MODE_FLAG_3D_TOP_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);
+	}
+}
+
+static const char *s3d_format_str(unsigned int format)
+{
+	switch(format) {
+	case DRM_MODE_FLAG_3D_TOP_BOTTOM:
+		return "TB";
+	case DRM_MODE_FLAG_3D_FRAME_PACKING:
+		return "FP";
+	}
+
+	return "Unknown format";
+}
+
+static void do_set_3d_format(struct connector *c, unsigned int format)
+{
+	uint32_t fb_id;
+	struct kmstest_fb fb_info;
+
+	snprintf(c->s3d_image, sizeof(c->s3d_image), "%d%s.png",
+		 c->mode.vdisplay, s3d_format_str(format));
+
+	adjust_3d_timings(&c->mode, format);
+	width = c->mode.hdisplay;
+	height = c->mode.vdisplay;
+
+	fb_id = kmstest_create_fb(drm_fd, width, height, bpp, depth,
+				  enable_tiling, &fb_info,
+				  paint_3d_image, c);
+
+	fb_ptr = gem_mmap(drm_fd, fb_info.gem_handle,
+			  fb_info.size, PROT_READ | PROT_WRITE);
+	assert(fb_ptr);
+
+	gem_close(drm_fd, fb_info.gem_handle);
+
+	kmstest_dump_mode(&c->mode);
+
+	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_modes(struct connector *c)
+{
+	int i;
+
+	if (depth <= 8)
+		bpp = 8;
+	else if (depth > 8 && depth <= 16)
+		bpp = 16;
+	else if (depth > 16 && depth <= 32)
+		bpp = 32;
+
+	connector_find_preferred_mode(c);
+	if (!c->mode_valid)
+		return;
+
+	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;
+
+		if (c->mode.flags & DRM_MODE_FLAG_INTERLACE)
+			continue;
+
+		s3d_formats = c->mode.flags & DRM_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 &= ~DRM_MODE_FLAG_3D_MASK;
+			c->mode.flags |= format;
+
+			do_set_3d_format(c, format);
+
+			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.
  *
@@ -592,11 +789,26 @@ int update_display(void)
 			set_mode(&connectors[c]);
 		}
 	}
+
+	if (test_all_modes || test_3d_modes) {
+		/* Find connectors that can expose 3D modes */
+		for (c = 0; c < resources->count_connectors; c++) {
+			connectors[c].id = resources->connectors[c];
+
+			if (!connector_expose_3d(connectors[c].id, TRUE))
+				continue;
+
+			set_3d_mods(&connectors[c]);
+
+			connector_expose_3d(connectors[c].id, FALSE);
+		}
+	}
+
 	drmModeFreeResources(resources);
 	return 1;
 }
 
-static char optstr[] = "hiaf:s:d:p:mrt";
+static char optstr[] = "3hiaf:s:d:p:mrt";
 
 static void __attribute__((noreturn)) usage(char *name)
 {
@@ -607,6 +819,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-f\t<clock MHz>,<hdisp>,<hsync-start>,<hsync-end>,<htotal>,\n");
@@ -663,6 +876,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':
 			dump_info = 1;
 			break;
@@ -710,7 +926,7 @@ int main(int argc, char **argv)
 		}
 	}
 	if (!test_all_modes && !force_mode && !dump_info &&
-	    !test_preferred_mode)
+	    !test_preferred_mode && !test_3d_modes)
 		test_all_modes = 1;
 
 	drm_fd = drm_open_any();
-- 
1.7.11.4



More information about the dri-devel mailing list