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>2012-10-12 15:00:58 +0100
commite823157fd03464eb69c9abd8838f7dbdec24d8c8 (patch)
treee281449f56940476bc3194cb59c54796819591ef
parentea6288aaccdb8341273ab8836663743e02bdc93c (diff)
tests/testdisplay: Test the stereo 3D modesstereo-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.c226
1 files changed, 221 insertions, 5 deletions
diff --git a/tests/testdisplay.c b/tests/testdisplay.c
index cd83d9c..1eb9310 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;
@@ -154,8 +155,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;
@@ -173,11 +217,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",
@@ -189,7 +235,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 "
@@ -200,6 +246,9 @@ static void dump_connectors_fd(int drmfd)
}
drmModeFreeConnector(connector);
+
+next:
+ connector_expose_3d(mode_resources->connectors[i], FALSE);
}
printf("\n");
@@ -563,6 +612,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.
*
@@ -601,11 +798,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_modes(&connectors[c]);
+
+ connector_expose_3d(connectors[c].id, FALSE);
+ }
+ }
+
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)
{
@@ -616,6 +828,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<number of the mode>\tonly test specified mode\n");
@@ -675,6 +888,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;
@@ -726,7 +942,7 @@ int main(int argc, char **argv)
}
}
if (!test_all_modes && !force_mode && !dump_info &&
- !test_preferred_mode && !only_one_mode)
+ !test_preferred_mode && !only_one_mode && !test_3d_modes)
test_all_modes = 1;
drm_fd = drm_open_any();