summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-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();