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

Kristian Høgsberg hoegsberg at gmail.com
Fri Sep 14 09:35:27 PDT 2012


On Wed, Sep 12, 2012 at 06:48:19PM +0100, Damien Lespiau wrote:
> 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/1080FP.png    | Bin 0 -> 2291944 bytes
>  tests/1080TB.png    | Bin 0 -> 1137594 bytes
>  tests/720FP.png     | Bin 0 -> 1088754 bytes
>  tests/720TB.png     | Bin 0 -> 555755 bytes
>  tests/testdisplay.c | 216 +++++++++++++++++++++++++++++++++++++++++++++++++++-
>  5 files changed, 213 insertions(+), 3 deletions(-)
>  create mode 100644 tests/1080FP.png
>  create mode 100644 tests/1080TB.png
>  create mode 100644 tests/720FP.png
>  create mode 100644 tests/720TB.png
> 
> diff --git a/tests/1080FP.png b/tests/1080FP.png

<snip stereoscopic base64>

> literal 0
> HcmV?d00001
> 
> diff --git a/tests/testdisplay.c b/tests/testdisplay.c
> index c52bb2f..77d1503 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,6 +154,11 @@ struct connector {
>  	drmModeConnector *connector;
>  	int crtc;
>  	int pipe;
> +
> +	/* stereo 3d */
> +	int s3d_format;
> +	uint32_t s3d_property_id;
> +	char s3d_image[32];
>  };
>  
>  static void dump_connectors_fd(int drmfd)
> @@ -554,6 +560,193 @@ 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 (drmModeConnectorSetProperty(drm_fd,
> +					c->id,
> +					c->s3d_property_id,
> +					format)) {
> +		fprintf(stderr, "failed to set \"select 3D mode\" "
> +			"property to %d: %s\n", 1, strerror(errno));
> +	}

I agree with Chris that this would be better done as part of the mode.
We can do it in a way that doesn't break backwards compatibility by
having an "please actually use the 3d mode bits" in the mode flags.
That way, the kernel can advertise 3d caps in the mode flags as it
does now, and you can select it by picking the 3d mode you want (oh, I
see, my previous enum vs bitfield comment was wrong) and setting the
"enable 3d" flags as well.  Existing KMS apps will just pass the mode
back to the kernel without the enable flag and work as usual.

Kristian

> +	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;
> +
> +	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);
> +
> +			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);
> +
> +	}
> +
> +	/* disable the HDMI info frames with the next mode set */
> +	if (drmModeConnectorSetProperty(drm_fd,
> +					c->id,
> +					c->s3d_property_id,
> +					0)) {
> +		fprintf(stderr, "failed to reset the \"select 3D mode\""
> +			" property\n");
> +	}
> +
> +	drmModeFreeEncoder(c->encoder);
> +	drmModeFreeConnector(c->connector);
> +}
> +
> +static bool connector_supports_3d(struct connector *c)
> +{
> +	drmModeConnector *connector;
> +	drmModePropertyRes *property;
> +	bool found = false;
> +	int i;
> +
> +	connector = drmModeGetConnector(drm_fd, c->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, "select 3D mode") == 0) {
> +			found = true;
> +			c->s3d_property_id = property->prop_id;
> +			drmModeFreeProperty(property);
> +			goto out;
> +		}
> +
> +		drmModeFreeProperty(property);
> +	}
> +
> +out:
> +	drmModeFreeConnector(connector);
> +	return found;
> +}
> +
>  /*
>   * Re-probe outputs and light up as many as possible.
>   *
> @@ -592,11 +785,24 @@ int update_display(void)
>  			set_mode(&connectors[c]);
>  		}
>  	}
> +
> +	if (test_all_modes || test_3d_modes) {
> +		/* Find connectors with the "select 3D mode" property */
> +		for (c = 0; c < resources->count_connectors; c++) {
> +			connectors[c].id = resources->connectors[c];
> +
> +			if (!connector_supports_3d(&connectors[c]))
> +				continue;
> +
> +			set_3d_mode(&connectors[c]);
> +		}
> +	}
> +
>  	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 +813,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 +870,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 +920,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
> 
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/dri-devel


More information about the dri-devel mailing list