modetest.c revision 22944501
118210155Smrg/*
218210155Smrg * DRM based mode setting test program
318210155Smrg * Copyright 2008 Tungsten Graphics
418210155Smrg *   Jakob Bornecrantz <jakob@tungstengraphics.com>
518210155Smrg * Copyright 2008 Intel Corporation
618210155Smrg *   Jesse Barnes <jesse.barnes@intel.com>
718210155Smrg *
818210155Smrg * Permission is hereby granted, free of charge, to any person obtaining a
918210155Smrg * copy of this software and associated documentation files (the "Software"),
1018210155Smrg * to deal in the Software without restriction, including without limitation
1118210155Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense,
1218210155Smrg * and/or sell copies of the Software, and to permit persons to whom the
1318210155Smrg * Software is furnished to do so, subject to the following conditions:
1418210155Smrg *
1518210155Smrg * The above copyright notice and this permission notice shall be included in
1618210155Smrg * all copies or substantial portions of the Software.
1718210155Smrg *
1818210155Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
1918210155Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2018210155Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2118210155Smrg * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2218210155Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
2318210155Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
2418210155Smrg * IN THE SOFTWARE.
2518210155Smrg */
2618210155Smrg
2718210155Smrg/*
2818210155Smrg * This fairly simple test program dumps output in a similar format to the
2918210155Smrg * "xrandr" tool everyone knows & loves.  It's necessarily slightly different
3018210155Smrg * since the kernel separates outputs into encoder and connector structures,
3118210155Smrg * each with their own unique ID.  The program also allows test testing of the
3218210155Smrg * memory management and mode setting APIs by allowing the user to specify a
3318210155Smrg * connector and mode to use for mode setting.  If all works as expected, a
3418210155Smrg * blue background should be painted on the monitor attached to the specified
3518210155Smrg * connector after the selected mode is set.
3618210155Smrg *
3718210155Smrg * TODO: use cairo to write the mode info on the selected output once
3818210155Smrg *       the mode has been programmed, along with possible test patterns.
3918210155Smrg */
4018210155Smrg#include "config.h"
4118210155Smrg
4218210155Smrg#include <assert.h>
4318210155Smrg#include <stdio.h>
4418210155Smrg#include <stdlib.h>
4518210155Smrg#include <stdint.h>
4618210155Smrg#include <unistd.h>
4718210155Smrg#include <string.h>
4818210155Smrg#include <errno.h>
4922944501Smrg#include <sys/poll.h>
5022944501Smrg#include <sys/time.h>
5118210155Smrg
5218210155Smrg#include "xf86drm.h"
5318210155Smrg#include "xf86drmMode.h"
5418210155Smrg#include "intel_bufmgr.h"
5522944501Smrg#include "i915_drm.h"
5618210155Smrg
5718210155Smrg#ifdef HAVE_CAIRO
5818210155Smrg#include <math.h>
5918210155Smrg#include <cairo.h>
6018210155Smrg#endif
6118210155Smrg
6218210155SmrgdrmModeRes *resources;
6318210155Smrgint fd, modes;
6418210155Smrg
6518210155Smrg#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
6618210155Smrg
6718210155Smrgstruct type_name {
6818210155Smrg	int type;
6918210155Smrg	char *name;
7018210155Smrg};
7118210155Smrg
7218210155Smrg#define type_name_fn(res) \
7318210155Smrgchar * res##_str(int type) {			\
7418210155Smrg	int i;						\
7518210155Smrg	for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
7618210155Smrg		if (res##_names[i].type == type)	\
7718210155Smrg			return res##_names[i].name;	\
7818210155Smrg	}						\
7918210155Smrg	return "(invalid)";				\
8018210155Smrg}
8118210155Smrg
8218210155Smrgstruct type_name encoder_type_names[] = {
8318210155Smrg	{ DRM_MODE_ENCODER_NONE, "none" },
8418210155Smrg	{ DRM_MODE_ENCODER_DAC, "DAC" },
8518210155Smrg	{ DRM_MODE_ENCODER_TMDS, "TMDS" },
8618210155Smrg	{ DRM_MODE_ENCODER_LVDS, "LVDS" },
8718210155Smrg	{ DRM_MODE_ENCODER_TVDAC, "TVDAC" },
8818210155Smrg};
8918210155Smrg
9018210155Smrgtype_name_fn(encoder_type)
9118210155Smrg
9218210155Smrgstruct type_name connector_status_names[] = {
9318210155Smrg	{ DRM_MODE_CONNECTED, "connected" },
9418210155Smrg	{ DRM_MODE_DISCONNECTED, "disconnected" },
9518210155Smrg	{ DRM_MODE_UNKNOWNCONNECTION, "unknown" },
9618210155Smrg};
9718210155Smrg
9818210155Smrgtype_name_fn(connector_status)
9918210155Smrg
10018210155Smrgstruct type_name connector_type_names[] = {
10118210155Smrg	{ DRM_MODE_CONNECTOR_Unknown, "unknown" },
10218210155Smrg	{ DRM_MODE_CONNECTOR_VGA, "VGA" },
10318210155Smrg	{ DRM_MODE_CONNECTOR_DVII, "DVI-I" },
10418210155Smrg	{ DRM_MODE_CONNECTOR_DVID, "DVI-D" },
10518210155Smrg	{ DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
10618210155Smrg	{ DRM_MODE_CONNECTOR_Composite, "composite" },
10718210155Smrg	{ DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
10818210155Smrg	{ DRM_MODE_CONNECTOR_LVDS, "LVDS" },
10918210155Smrg	{ DRM_MODE_CONNECTOR_Component, "component" },
11018210155Smrg	{ DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
11118210155Smrg	{ DRM_MODE_CONNECTOR_DisplayPort, "displayport" },
11218210155Smrg	{ DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
11318210155Smrg	{ DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
11418210155Smrg};
11518210155Smrg
11618210155Smrgtype_name_fn(connector_type)
11718210155Smrg
11818210155Smrgvoid dump_encoders(void)
11918210155Smrg{
12018210155Smrg	drmModeEncoder *encoder;
12118210155Smrg	int i;
12218210155Smrg
12318210155Smrg	printf("Encoders:\n");
12418210155Smrg	printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
12518210155Smrg	for (i = 0; i < resources->count_encoders; i++) {
12618210155Smrg		encoder = drmModeGetEncoder(fd, resources->encoders[i]);
12718210155Smrg
12818210155Smrg		if (!encoder) {
12918210155Smrg			fprintf(stderr, "could not get encoder %i: %s\n",
13018210155Smrg				resources->encoders[i], strerror(errno));
13118210155Smrg			continue;
13218210155Smrg		}
13318210155Smrg		printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
13418210155Smrg		       encoder->encoder_id,
13518210155Smrg		       encoder->crtc_id,
13618210155Smrg		       encoder_type_str(encoder->encoder_type),
13718210155Smrg		       encoder->possible_crtcs,
13818210155Smrg		       encoder->possible_clones);
13918210155Smrg		drmModeFreeEncoder(encoder);
14018210155Smrg	}
14118210155Smrg	printf("\n");
14218210155Smrg}
14318210155Smrg
14418210155Smrgvoid dump_mode(drmModeModeInfo *mode)
14518210155Smrg{
14622944501Smrg	printf("  %s %d %d %d %d %d %d %d %d %d\n",
14718210155Smrg	       mode->name,
14822944501Smrg	       mode->vrefresh,
14918210155Smrg	       mode->hdisplay,
15018210155Smrg	       mode->hsync_start,
15118210155Smrg	       mode->hsync_end,
15218210155Smrg	       mode->htotal,
15318210155Smrg	       mode->vdisplay,
15418210155Smrg	       mode->vsync_start,
15518210155Smrg	       mode->vsync_end,
15618210155Smrg	       mode->vtotal);
15718210155Smrg}
15818210155Smrg
15918210155Smrgstatic void
16018210155Smrgdump_props(drmModeConnector *connector)
16118210155Smrg{
16218210155Smrg	drmModePropertyPtr props;
16318210155Smrg	int i;
16418210155Smrg
16518210155Smrg	for (i = 0; i < connector->count_props; i++) {
16618210155Smrg		props = drmModeGetProperty(fd, connector->props[i]);
16718210155Smrg		printf("\t%s, flags %d\n", props->name, props->flags);
16818210155Smrg		drmModeFreeProperty(props);
16918210155Smrg	}
17018210155Smrg}
17118210155Smrg
17218210155Smrgvoid dump_connectors(void)
17318210155Smrg{
17418210155Smrg	drmModeConnector *connector;
17518210155Smrg	int i, j;
17618210155Smrg
17718210155Smrg	printf("Connectors:\n");
17822944501Smrg	printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n");
17918210155Smrg	for (i = 0; i < resources->count_connectors; i++) {
18018210155Smrg		connector = drmModeGetConnector(fd, resources->connectors[i]);
18118210155Smrg
18218210155Smrg		if (!connector) {
18318210155Smrg			fprintf(stderr, "could not get connector %i: %s\n",
18418210155Smrg				resources->connectors[i], strerror(errno));
18518210155Smrg			continue;
18618210155Smrg		}
18718210155Smrg
18822944501Smrg		printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t",
18918210155Smrg		       connector->connector_id,
19018210155Smrg		       connector->encoder_id,
19118210155Smrg		       connector_status_str(connector->connection),
19218210155Smrg		       connector_type_str(connector->connector_type),
19318210155Smrg		       connector->mmWidth, connector->mmHeight,
19418210155Smrg		       connector->count_modes);
19518210155Smrg
19622944501Smrg		for (j = 0; j < connector->count_encoders; j++)
19722944501Smrg			printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
19822944501Smrg		printf("\n");
19922944501Smrg
20018210155Smrg		if (!connector->count_modes)
20118210155Smrg			continue;
20218210155Smrg
20318210155Smrg		printf("  modes:\n");
20418210155Smrg		printf("  name refresh (Hz) hdisp hss hse htot vdisp "
20518210155Smrg		       "vss vse vtot)\n");
20618210155Smrg		for (j = 0; j < connector->count_modes; j++)
20718210155Smrg			dump_mode(&connector->modes[j]);
20818210155Smrg
20918210155Smrg		printf("  props:\n");
21018210155Smrg		dump_props(connector);
21122944501Smrg
21222944501Smrg		drmModeFreeConnector(connector);
21318210155Smrg	}
21418210155Smrg	printf("\n");
21518210155Smrg}
21618210155Smrg
21718210155Smrgvoid dump_crtcs(void)
21818210155Smrg{
21918210155Smrg	drmModeCrtc *crtc;
22018210155Smrg	int i;
22118210155Smrg
22218210155Smrg	printf("CRTCs:\n");
22318210155Smrg	printf("id\tfb\tpos\tsize\n");
22418210155Smrg	for (i = 0; i < resources->count_crtcs; i++) {
22518210155Smrg		crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
22618210155Smrg
22718210155Smrg		if (!crtc) {
22818210155Smrg			fprintf(stderr, "could not get crtc %i: %s\n",
22918210155Smrg				resources->crtcs[i], strerror(errno));
23018210155Smrg			continue;
23118210155Smrg		}
23218210155Smrg		printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
23318210155Smrg		       crtc->crtc_id,
23418210155Smrg		       crtc->buffer_id,
23518210155Smrg		       crtc->x, crtc->y,
23618210155Smrg		       crtc->width, crtc->height);
23718210155Smrg		dump_mode(&crtc->mode);
23818210155Smrg
23918210155Smrg		drmModeFreeCrtc(crtc);
24018210155Smrg	}
24118210155Smrg	printf("\n");
24218210155Smrg}
24318210155Smrg
24418210155Smrgvoid dump_framebuffers(void)
24518210155Smrg{
24618210155Smrg	drmModeFB *fb;
24718210155Smrg	int i;
24818210155Smrg
24918210155Smrg	printf("Frame buffers:\n");
25018210155Smrg	printf("id\tsize\tpitch\n");
25118210155Smrg	for (i = 0; i < resources->count_fbs; i++) {
25218210155Smrg		fb = drmModeGetFB(fd, resources->fbs[i]);
25318210155Smrg
25418210155Smrg		if (!fb) {
25518210155Smrg			fprintf(stderr, "could not get fb %i: %s\n",
25618210155Smrg				resources->fbs[i], strerror(errno));
25718210155Smrg			continue;
25818210155Smrg		}
25922944501Smrg		printf("%u\t(%ux%u)\t%u\n",
26018210155Smrg		       fb->fb_id,
26122944501Smrg		       fb->width, fb->height,
26222944501Smrg		       fb->pitch);
26318210155Smrg
26418210155Smrg		drmModeFreeFB(fb);
26518210155Smrg	}
26618210155Smrg	printf("\n");
26718210155Smrg}
26818210155Smrg
26918210155Smrg/*
27018210155Smrg * Mode setting with the kernel interfaces is a bit of a chore.
27118210155Smrg * First you have to find the connector in question and make sure the
27218210155Smrg * requested mode is available.
27318210155Smrg * Then you need to find the encoder attached to that connector so you
27418210155Smrg * can bind it with a free crtc.
27518210155Smrg */
27618210155Smrgstruct connector {
27722944501Smrg	uint32_t id;
27818210155Smrg	char mode_str[64];
27918210155Smrg	drmModeModeInfo *mode;
28018210155Smrg	drmModeEncoder *encoder;
28118210155Smrg	int crtc;
28222944501Smrg	unsigned int fb_id[2], current_fb_id;
28322944501Smrg	struct timeval start;
28422944501Smrg
28522944501Smrg	int swap_count;
28618210155Smrg};
28718210155Smrg
28818210155Smrgstatic void
28918210155Smrgconnector_find_mode(struct connector *c)
29018210155Smrg{
29118210155Smrg	drmModeConnector *connector;
29222944501Smrg	int i, j;
29318210155Smrg
29418210155Smrg	/* First, find the connector & mode */
29518210155Smrg	c->mode = NULL;
29618210155Smrg	for (i = 0; i < resources->count_connectors; i++) {
29718210155Smrg		connector = drmModeGetConnector(fd, resources->connectors[i]);
29818210155Smrg
29918210155Smrg		if (!connector) {
30018210155Smrg			fprintf(stderr, "could not get connector %i: %s\n",
30118210155Smrg				resources->connectors[i], strerror(errno));
30218210155Smrg			drmModeFreeConnector(connector);
30318210155Smrg			continue;
30418210155Smrg		}
30518210155Smrg
30618210155Smrg		if (!connector->count_modes) {
30718210155Smrg			drmModeFreeConnector(connector);
30818210155Smrg			continue;
30918210155Smrg		}
31018210155Smrg
31118210155Smrg		if (connector->connector_id != c->id) {
31218210155Smrg			drmModeFreeConnector(connector);
31318210155Smrg			continue;
31418210155Smrg		}
31518210155Smrg
31618210155Smrg		for (j = 0; j < connector->count_modes; j++) {
31718210155Smrg			c->mode = &connector->modes[j];
31818210155Smrg			if (!strcmp(c->mode->name, c->mode_str))
31918210155Smrg				break;
32018210155Smrg		}
32118210155Smrg
32218210155Smrg		/* Found it, break out */
32318210155Smrg		if (c->mode)
32418210155Smrg			break;
32518210155Smrg
32618210155Smrg		drmModeFreeConnector(connector);
32718210155Smrg	}
32818210155Smrg
32918210155Smrg	if (!c->mode) {
33018210155Smrg		fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
33118210155Smrg		return;
33218210155Smrg	}
33318210155Smrg
33418210155Smrg	/* Now get the encoder */
33518210155Smrg	for (i = 0; i < resources->count_encoders; i++) {
33618210155Smrg		c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
33718210155Smrg
33818210155Smrg		if (!c->encoder) {
33918210155Smrg			fprintf(stderr, "could not get encoder %i: %s\n",
34018210155Smrg				resources->encoders[i], strerror(errno));
34118210155Smrg			drmModeFreeEncoder(c->encoder);
34218210155Smrg			continue;
34318210155Smrg		}
34418210155Smrg
34518210155Smrg		if (c->encoder->encoder_id  == connector->encoder_id)
34618210155Smrg			break;
34718210155Smrg
34818210155Smrg		drmModeFreeEncoder(c->encoder);
34918210155Smrg	}
35018210155Smrg
35118210155Smrg	if (c->crtc == -1)
35218210155Smrg		c->crtc = c->encoder->crtc_id;
35318210155Smrg}
35418210155Smrg
35518210155Smrg#ifdef HAVE_CAIRO
35618210155Smrg
35718210155Smrgstatic int
35818210155Smrgcreate_test_buffer(drm_intel_bufmgr *bufmgr,
35918210155Smrg		   int width, int height, int *stride_out, drm_intel_bo **bo_out)
36018210155Smrg{
36118210155Smrg	drm_intel_bo *bo;
36218210155Smrg	unsigned int *fb_ptr;
36322944501Smrg	int size, i, stride;
36418210155Smrg	div_t d;
36518210155Smrg	cairo_surface_t *surface;
36618210155Smrg	cairo_t *cr;
36718210155Smrg	char buf[64];
36818210155Smrg	int x, y;
36918210155Smrg
37018210155Smrg	surface = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
37118210155Smrg	stride = cairo_image_surface_get_stride(surface);
37218210155Smrg	size = stride * height;
37318210155Smrg	fb_ptr = (unsigned int *) cairo_image_surface_get_data(surface);
37418210155Smrg
37518210155Smrg	/* paint the buffer with colored tiles */
37618210155Smrg	for (i = 0; i < width * height; i++) {
37718210155Smrg		d = div(i, width);
37818210155Smrg		fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
37918210155Smrg	}
38018210155Smrg
38118210155Smrg	cr = cairo_create(surface);
38218210155Smrg	cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
38318210155Smrg	for (x = 0; x < width; x += 250)
38418210155Smrg		for (y = 0; y < height; y += 250) {
38518210155Smrg			cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
38618210155Smrg			cairo_move_to(cr, x, y - 20);
38718210155Smrg			cairo_line_to(cr, x, y + 20);
38818210155Smrg			cairo_move_to(cr, x - 20, y);
38918210155Smrg			cairo_line_to(cr, x + 20, y);
39018210155Smrg			cairo_new_sub_path(cr);
39118210155Smrg			cairo_arc(cr, x, y, 10, 0, M_PI * 2);
39218210155Smrg			cairo_set_line_width(cr, 4);
39318210155Smrg			cairo_set_source_rgb(cr, 0, 0, 0);
39418210155Smrg			cairo_stroke_preserve(cr);
39518210155Smrg			cairo_set_source_rgb(cr, 1, 1, 1);
39618210155Smrg			cairo_set_line_width(cr, 2);
39718210155Smrg			cairo_stroke(cr);
39818210155Smrg			snprintf(buf, sizeof buf, "%d, %d", x, y);
39918210155Smrg			cairo_move_to(cr, x + 20, y + 20);
40018210155Smrg			cairo_text_path(cr, buf);
40118210155Smrg			cairo_set_source_rgb(cr, 0, 0, 0);
40218210155Smrg			cairo_stroke_preserve(cr);
40318210155Smrg			cairo_set_source_rgb(cr, 1, 1, 1);
40418210155Smrg			cairo_fill(cr);
40518210155Smrg		}
40618210155Smrg
40718210155Smrg	cairo_destroy(cr);
40818210155Smrg
40918210155Smrg	bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096);
41018210155Smrg	if (!bo) {
41118210155Smrg		fprintf(stderr, "failed to alloc buffer: %s\n",
41218210155Smrg			strerror(errno));
41318210155Smrg		return -1;
41418210155Smrg	}
41518210155Smrg
41618210155Smrg	drm_intel_bo_subdata(bo, 0, size, fb_ptr);
41718210155Smrg
41818210155Smrg	cairo_surface_destroy(surface);
41918210155Smrg
42018210155Smrg	*bo_out = bo;
42118210155Smrg	*stride_out = stride;
42218210155Smrg
42318210155Smrg	return 0;
42418210155Smrg}
42518210155Smrg
42618210155Smrg#else
42718210155Smrg
42818210155Smrgstatic int
42918210155Smrgcreate_test_buffer(drm_intel_bufmgr *bufmgr,
43018210155Smrg		   int width, int height, int *stride_out, drm_intel_bo **bo_out)
43118210155Smrg{
43218210155Smrg	drm_intel_bo *bo;
43318210155Smrg	unsigned int *fb_ptr;
43418210155Smrg	int size, ret, i, stride;
43518210155Smrg	div_t d;
43618210155Smrg
43718210155Smrg	/* Mode size at 32 bpp */
43818210155Smrg	stride = width * 4;
43918210155Smrg	size = stride * height;
44018210155Smrg
44118210155Smrg	bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096);
44218210155Smrg	if (!bo) {
44318210155Smrg		fprintf(stderr, "failed to alloc buffer: %s\n",
44418210155Smrg			strerror(errno));
44518210155Smrg		return -1;
44618210155Smrg	}
44718210155Smrg
44818210155Smrg	ret = drm_intel_gem_bo_map_gtt(bo);
44918210155Smrg	if (ret) {
45018210155Smrg		fprintf(stderr, "failed to GTT map buffer: %s\n",
45118210155Smrg			strerror(errno));
45218210155Smrg		return -1;
45318210155Smrg	}
45418210155Smrg
45518210155Smrg	fb_ptr = bo->virtual;
45618210155Smrg
45718210155Smrg	/* paint the buffer with colored tiles */
45818210155Smrg	for (i = 0; i < width * height; i++) {
45918210155Smrg		d = div(i, width);
46018210155Smrg		fb_ptr[i] = 0x00130502 * (d.quot >> 6) + 0x000a1120 * (d.rem >> 6);
46118210155Smrg	}
46222944501Smrg	drm_intel_gem_bo_unmap_gtt(bo);
46318210155Smrg
46418210155Smrg	*bo_out = bo;
46518210155Smrg	*stride_out = stride;
46618210155Smrg
46718210155Smrg	return 0;
46818210155Smrg}
46918210155Smrg
47018210155Smrg#endif
47118210155Smrg
47222944501Smrgstatic int
47322944501Smrgcreate_grey_buffer(drm_intel_bufmgr *bufmgr,
47422944501Smrg		   int width, int height, int *stride_out, drm_intel_bo **bo_out)
47522944501Smrg{
47622944501Smrg	drm_intel_bo *bo;
47722944501Smrg	int size, ret, stride;
47822944501Smrg
47922944501Smrg	/* Mode size at 32 bpp */
48022944501Smrg	stride = width * 4;
48122944501Smrg	size = stride * height;
48222944501Smrg
48322944501Smrg	bo = drm_intel_bo_alloc(bufmgr, "frontbuffer", size, 4096);
48422944501Smrg	if (!bo) {
48522944501Smrg		fprintf(stderr, "failed to alloc buffer: %s\n",
48622944501Smrg			strerror(errno));
48722944501Smrg		return -1;
48822944501Smrg	}
48922944501Smrg
49022944501Smrg	ret = drm_intel_gem_bo_map_gtt(bo);
49122944501Smrg	if (ret) {
49222944501Smrg		fprintf(stderr, "failed to GTT map buffer: %s\n",
49322944501Smrg			strerror(errno));
49422944501Smrg		return -1;
49522944501Smrg	}
49622944501Smrg
49722944501Smrg	memset(bo->virtual, 0x77, size);
49822944501Smrg	drm_intel_gem_bo_unmap_gtt(bo);
49922944501Smrg
50022944501Smrg	*bo_out = bo;
50122944501Smrg	*stride_out = stride;
50222944501Smrg
50322944501Smrg	return 0;
50422944501Smrg}
50522944501Smrg
50622944501Smrgvoid
50722944501Smrgpage_flip_handler(int fd, unsigned int frame,
50822944501Smrg		  unsigned int sec, unsigned int usec, void *data)
50922944501Smrg{
51022944501Smrg	struct connector *c;
51122944501Smrg	unsigned int new_fb_id;
51222944501Smrg	struct timeval end;
51322944501Smrg	double t;
51422944501Smrg
51522944501Smrg	c = data;
51622944501Smrg	if (c->current_fb_id == c->fb_id[0])
51722944501Smrg		new_fb_id = c->fb_id[1];
51822944501Smrg	else
51922944501Smrg		new_fb_id = c->fb_id[0];
52022944501Smrg
52122944501Smrg	drmModePageFlip(fd, c->crtc, new_fb_id,
52222944501Smrg			DRM_MODE_PAGE_FLIP_EVENT, c);
52322944501Smrg	c->current_fb_id = new_fb_id;
52422944501Smrg	c->swap_count++;
52522944501Smrg	if (c->swap_count == 60) {
52622944501Smrg		gettimeofday(&end, NULL);
52722944501Smrg		t = end.tv_sec + end.tv_usec * 1e-6 -
52822944501Smrg			(c->start.tv_sec + c->start.tv_usec * 1e-6);
52922944501Smrg		fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t);
53022944501Smrg		c->swap_count = 0;
53122944501Smrg		c->start = end;
53222944501Smrg	}
53322944501Smrg}
53422944501Smrg
53518210155Smrgstatic void
53622944501Smrgset_mode(struct connector *c, int count, int page_flip)
53718210155Smrg{
53818210155Smrg	drm_intel_bufmgr *bufmgr;
53922944501Smrg	drm_intel_bo *bo, *other_bo;
54022944501Smrg	unsigned int fb_id, other_fb_id;
54122944501Smrg	int i, ret, width, height, x, stride;
54222944501Smrg	drmEventContext evctx;
54318210155Smrg
54418210155Smrg	width = 0;
54518210155Smrg	height = 0;
54618210155Smrg	for (i = 0; i < count; i++) {
54718210155Smrg		connector_find_mode(&c[i]);
54818210155Smrg		if (c[i].mode == NULL)
54918210155Smrg			continue;
55018210155Smrg		width += c[i].mode->hdisplay;
55118210155Smrg		if (height < c[i].mode->vdisplay)
55218210155Smrg			height = c[i].mode->vdisplay;
55318210155Smrg	}
55418210155Smrg
55518210155Smrg	bufmgr = drm_intel_bufmgr_gem_init(fd, 2<<20);
55618210155Smrg	if (!bufmgr) {
55718210155Smrg		fprintf(stderr, "failed to init bufmgr: %s\n", strerror(errno));
55818210155Smrg		return;
55918210155Smrg	}
56018210155Smrg
56118210155Smrg	if (create_test_buffer(bufmgr, width, height, &stride, &bo))
56218210155Smrg		return;
56318210155Smrg
56418210155Smrg	ret = drmModeAddFB(fd, width, height, 32, 32, stride, bo->handle,
56518210155Smrg			   &fb_id);
56618210155Smrg	if (ret) {
56718210155Smrg		fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
56818210155Smrg		return;
56918210155Smrg	}
57018210155Smrg
57118210155Smrg	x = 0;
57218210155Smrg	for (i = 0; i < count; i++) {
57318210155Smrg		if (c[i].mode == NULL)
57418210155Smrg			continue;
57518210155Smrg
57618210155Smrg		printf("setting mode %s on connector %d, crtc %d\n",
57718210155Smrg		       c[i].mode_str, c[i].id, c[i].crtc);
57818210155Smrg
57918210155Smrg		ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0,
58018210155Smrg				     &c[i].id, 1, c[i].mode);
58118210155Smrg		x += c[i].mode->hdisplay;
58218210155Smrg
58318210155Smrg		if (ret) {
58418210155Smrg			fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
58518210155Smrg			return;
58618210155Smrg		}
58718210155Smrg	}
58822944501Smrg
58922944501Smrg	if (!page_flip)
59022944501Smrg		return;
59122944501Smrg
59222944501Smrg	if (create_grey_buffer(bufmgr, width, height, &stride, &other_bo))
59322944501Smrg		return;
59422944501Smrg
59522944501Smrg	ret = drmModeAddFB(fd, width, height, 32, 32, stride, other_bo->handle,
59622944501Smrg			   &other_fb_id);
59722944501Smrg	if (ret) {
59822944501Smrg		fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
59922944501Smrg		return;
60022944501Smrg	}
60122944501Smrg
60222944501Smrg	for (i = 0; i < count; i++) {
60322944501Smrg		if (c[i].mode == NULL)
60422944501Smrg			continue;
60522944501Smrg
60622944501Smrg		drmModePageFlip(fd, c[i].crtc, other_fb_id,
60722944501Smrg				DRM_MODE_PAGE_FLIP_EVENT, &c[i]);
60822944501Smrg		gettimeofday(&c[i].start, NULL);
60922944501Smrg		c[i].swap_count = 0;
61022944501Smrg		c[i].fb_id[0] = fb_id;
61122944501Smrg		c[i].fb_id[1] = other_fb_id;
61222944501Smrg		c[i].current_fb_id = fb_id;
61322944501Smrg	}
61422944501Smrg
61522944501Smrg	memset(&evctx, 0, sizeof evctx);
61622944501Smrg	evctx.version = DRM_EVENT_CONTEXT_VERSION;
61722944501Smrg	evctx.vblank_handler = NULL;
61822944501Smrg	evctx.page_flip_handler = page_flip_handler;
61922944501Smrg
62022944501Smrg	while (1) {
62122944501Smrg#if 0
62222944501Smrg		struct pollfd pfd[2];
62322944501Smrg
62422944501Smrg		pfd[0].fd = 0;
62522944501Smrg		pfd[0].events = POLLIN;
62622944501Smrg		pfd[1].fd = fd;
62722944501Smrg		pfd[1].events = POLLIN;
62822944501Smrg
62922944501Smrg		if (poll(pfd, 2, -1) < 0) {
63022944501Smrg			fprintf(stderr, "poll error\n");
63122944501Smrg			break;
63222944501Smrg		}
63322944501Smrg
63422944501Smrg		if (pfd[0].revents)
63522944501Smrg			break;
63622944501Smrg#else
63722944501Smrg		struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
63822944501Smrg		fd_set fds;
63922944501Smrg		int ret;
64022944501Smrg
64122944501Smrg		FD_ZERO(&fds);
64222944501Smrg		FD_SET(0, &fds);
64322944501Smrg		FD_SET(fd, &fds);
64422944501Smrg		ret = select(fd + 1, &fds, NULL, NULL, &timeout);
64522944501Smrg
64622944501Smrg		if (ret <= 0) {
64722944501Smrg			fprintf(stderr, "select timed out or error (ret %d)\n",
64822944501Smrg				ret);
64922944501Smrg			continue;
65022944501Smrg		} else if (FD_ISSET(0, &fds)) {
65122944501Smrg			break;
65222944501Smrg		}
65322944501Smrg#endif
65422944501Smrg
65522944501Smrg		drmHandleEvent(fd, &evctx);
65622944501Smrg	}
65718210155Smrg}
65818210155Smrg
65918210155Smrgextern char *optarg;
66018210155Smrgextern int optind, opterr, optopt;
66122944501Smrgstatic char optstr[] = "ecpmfs:v";
66218210155Smrg
66318210155Smrgvoid usage(char *name)
66418210155Smrg{
66518210155Smrg	fprintf(stderr, "usage: %s [-ecpmf]\n", name);
66618210155Smrg	fprintf(stderr, "\t-e\tlist encoders\n");
66718210155Smrg	fprintf(stderr, "\t-c\tlist connectors\n");
66818210155Smrg	fprintf(stderr, "\t-p\tlist CRTCs (pipes)\n");
66918210155Smrg	fprintf(stderr, "\t-m\tlist modes\n");
67018210155Smrg	fprintf(stderr, "\t-f\tlist framebuffers\n");
67122944501Smrg	fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
67218210155Smrg	fprintf(stderr, "\t-s <connector_id>:<mode>\tset a mode\n");
67318210155Smrg	fprintf(stderr, "\t-s <connector_id>@<crtc_id>:<mode>\tset a mode\n");
67418210155Smrg	fprintf(stderr, "\n\tDefault is to dump all info.\n");
67518210155Smrg	exit(0);
67618210155Smrg}
67718210155Smrg
67818210155Smrg#define dump_resource(res) if (res) dump_##res()
67918210155Smrg
68022944501Smrgstatic int page_flipping_supported(int fd)
68122944501Smrg{
68222944501Smrg	int ret, value;
68322944501Smrg	struct drm_i915_getparam gp;
68422944501Smrg
68522944501Smrg	gp.param = I915_PARAM_HAS_PAGEFLIPPING;
68622944501Smrg	gp.value = &value;
68722944501Smrg
68822944501Smrg	ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
68922944501Smrg	if (ret) {
69022944501Smrg		fprintf(stderr, "drm_i915_getparam: %m\n");
69122944501Smrg		return 0;
69222944501Smrg	}
69322944501Smrg
69422944501Smrg	return *gp.value;
69522944501Smrg}
69622944501Smrg
69718210155Smrgint main(int argc, char **argv)
69818210155Smrg{
69918210155Smrg	int c;
70018210155Smrg	int encoders = 0, connectors = 0, crtcs = 0, framebuffers = 0;
70122944501Smrg	int test_vsync = 0;
70222944501Smrg	char *modules[] = { "i915", "radeon", "nouveau" };
70322944501Smrg	char *modeset = NULL;
70422944501Smrg	int i, count = 0;
70518210155Smrg	struct connector con_args[2];
70618210155Smrg
70718210155Smrg	opterr = 0;
70818210155Smrg	while ((c = getopt(argc, argv, optstr)) != -1) {
70918210155Smrg		switch (c) {
71018210155Smrg		case 'e':
71118210155Smrg			encoders = 1;
71218210155Smrg			break;
71318210155Smrg		case 'c':
71418210155Smrg			connectors = 1;
71518210155Smrg			break;
71618210155Smrg		case 'p':
71718210155Smrg			crtcs = 1;
71818210155Smrg			break;
71918210155Smrg		case 'm':
72018210155Smrg			modes = 1;
72118210155Smrg			break;
72218210155Smrg		case 'f':
72318210155Smrg			framebuffers = 1;
72418210155Smrg			break;
72522944501Smrg		case 'v':
72622944501Smrg			test_vsync = 1;
72722944501Smrg			break;
72818210155Smrg		case 's':
72918210155Smrg			modeset = strdup(optarg);
73018210155Smrg			con_args[count].crtc = -1;
73118210155Smrg			if (sscanf(optarg, "%d:%64s",
73218210155Smrg				   &con_args[count].id,
73322944501Smrg				   con_args[count].mode_str) != 2 &&
73418210155Smrg			    sscanf(optarg, "%d@%d:%64s",
73518210155Smrg				   &con_args[count].id,
73618210155Smrg				   &con_args[count].crtc,
73722944501Smrg				   con_args[count].mode_str) != 3)
73818210155Smrg				usage(argv[0]);
73918210155Smrg			count++;
74018210155Smrg			break;
74118210155Smrg		default:
74218210155Smrg			usage(argv[0]);
74318210155Smrg			break;
74418210155Smrg		}
74518210155Smrg	}
74618210155Smrg
74718210155Smrg	if (argc == 1)
74818210155Smrg		encoders = connectors = crtcs = modes = framebuffers = 1;
74918210155Smrg
75018210155Smrg	for (i = 0; i < ARRAY_SIZE(modules); i++) {
75118210155Smrg		printf("trying to load module %s...", modules[i]);
75218210155Smrg		fd = drmOpen(modules[i], NULL);
75318210155Smrg		if (fd < 0) {
75418210155Smrg			printf("failed.\n");
75518210155Smrg		} else {
75618210155Smrg			printf("success.\n");
75718210155Smrg			break;
75818210155Smrg		}
75918210155Smrg	}
76018210155Smrg
76122944501Smrg	if (test_vsync && !page_flipping_supported(fd)) {
76222944501Smrg		fprintf(stderr, "page flipping not supported by drm.\n");
76322944501Smrg		return -1;
76422944501Smrg	}
76522944501Smrg
76618210155Smrg	if (i == ARRAY_SIZE(modules)) {
76718210155Smrg		fprintf(stderr, "failed to load any modules, aborting.\n");
76818210155Smrg		return -1;
76918210155Smrg	}
77018210155Smrg
77118210155Smrg	resources = drmModeGetResources(fd);
77218210155Smrg	if (!resources) {
77318210155Smrg		fprintf(stderr, "drmModeGetResources failed: %s\n",
77418210155Smrg			strerror(errno));
77518210155Smrg		drmClose(fd);
77618210155Smrg		return 1;
77718210155Smrg	}
77818210155Smrg
77918210155Smrg	dump_resource(encoders);
78018210155Smrg	dump_resource(connectors);
78118210155Smrg	dump_resource(crtcs);
78218210155Smrg	dump_resource(framebuffers);
78318210155Smrg
78418210155Smrg	if (count > 0) {
78522944501Smrg		set_mode(con_args, count, test_vsync);
78618210155Smrg		getchar();
78718210155Smrg	}
78818210155Smrg
78918210155Smrg	drmModeFreeResources(resources);
79018210155Smrg
79118210155Smrg	return 0;
79218210155Smrg}
793