2 * Copyright 2010 Intel Corporation
3 * Jesse Barnes <jesse.barnes@intel.com>
5 * Permission is hereby granted, free of charge, to any person obtaining a
6 * copy of this software and associated documentation files (the "Software"),
7 * to deal in the Software without restriction, including without limitation
8 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 * and/or sell copies of the Software, and to permit persons to whom the
10 * Software is furnished to do so, subject to the following conditions:
12 * The above copyright notice and this permission notice shall be included in
13 * all copies or substantial portions of the Software.
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
25 * This program is intended for testing of display functionality. It should
26 * allow for testing of
29 * - clone & twin modes
31 * - test patterns & pixel generators
32 * Additional programs can test the detected outputs against VBT provided
33 * device lists (both docked & undocked).
36 * - pixel generator in transcoder
37 * - test pattern reg in pipe
38 * - test patterns on outputs (e.g. TV)
39 * - handle hotplug (leaks crtcs, can't handle clones)
41 * - expose output specific controls
42 * - e.g. DDC-CI brightness
45 * - DP commands (e.g. poweroff)
46 * - verify outputs against VBT/physical connectors
64 #include <sys/ioctl.h>
67 #include "xf86drmMode.h"
70 #if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY)
72 #include "drm_fourcc.h"
75 struct udev_monitor *uevent_monitor;
76 drmModeRes *resources;
78 int dump_info = 0, test_all_modes =0, test_preferred_mode = 0, force_mode = 0,
79 test_plane, enable_tiling;
80 int sleep_between_modes = 5;
81 uint32_t depth = 24, stride, bpp;
85 int force_hsync_start;
89 int force_vsync_start;
93 int crtc_x, crtc_y, crtc_w, crtc_h, width, height;
94 unsigned int plane_fb_id;
95 unsigned int plane_crtc_id;
96 unsigned int plane_id;
97 int plane_width, plane_height;
98 static const uint32_t SPRITE_COLOR_KEY = 0x00aaaaaa;
101 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
108 #define type_name_fn(res) \
109 static const char * res##_str(int type) { \
111 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
112 if (res##_names[i].type == type) \
113 return res##_names[i].name; \
115 return "(invalid)"; \
118 struct type_name encoder_type_names[] = {
119 { DRM_MODE_ENCODER_NONE, "none" },
120 { DRM_MODE_ENCODER_DAC, "DAC" },
121 { DRM_MODE_ENCODER_TMDS, "TMDS" },
122 { DRM_MODE_ENCODER_LVDS, "LVDS" },
123 { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
126 type_name_fn(encoder_type)
128 struct type_name connector_status_names[] = {
129 { DRM_MODE_CONNECTED, "connected" },
130 { DRM_MODE_DISCONNECTED, "disconnected" },
131 { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
134 type_name_fn(connector_status)
136 struct type_name connector_type_names[] = {
137 { DRM_MODE_CONNECTOR_Unknown, "unknown" },
138 { DRM_MODE_CONNECTOR_VGA, "VGA" },
139 { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
140 { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
141 { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
142 { DRM_MODE_CONNECTOR_Composite, "composite" },
143 { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
144 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
145 { DRM_MODE_CONNECTOR_Component, "component" },
146 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
147 { DRM_MODE_CONNECTOR_DisplayPort, "DisplayPort" },
148 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
149 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
150 { DRM_MODE_CONNECTOR_TV, "TV" },
151 { DRM_MODE_CONNECTOR_eDP, "Embedded DisplayPort" },
154 type_name_fn(connector_type)
157 * Mode setting with the kernel interfaces is a bit of a chore.
158 * First you have to find the connector in question and make sure the
159 * requested mode is available.
160 * Then you need to find the encoder attached to that connector so you
161 * can bind it with a free crtc.
166 drmModeModeInfo mode;
167 drmModeEncoder *encoder;
168 drmModeConnector *connector;
173 static void dump_mode(drmModeModeInfo *mode)
175 printf(" %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d\n",
191 static void dump_connectors(void)
195 printf("Connectors:\n");
196 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\n");
197 for (i = 0; i < resources->count_connectors; i++) {
198 drmModeConnector *connector;
200 connector = drmModeGetConnector(fd, resources->connectors[i]);
202 fprintf(stderr, "could not get connector %i: %s\n",
203 resources->connectors[i], strerror(errno));
207 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\n",
208 connector->connector_id,
209 connector->encoder_id,
210 connector_status_str(connector->connection),
211 connector_type_str(connector->connector_type),
212 connector->mmWidth, connector->mmHeight,
213 connector->count_modes);
215 if (!connector->count_modes)
219 printf(" name refresh (Hz) hdisp hss hse htot vdisp "
220 "vss vse vtot flags type clock\n");
221 for (j = 0; j < connector->count_modes; j++)
222 dump_mode(&connector->modes[j]);
224 drmModeFreeConnector(connector);
229 static void dump_crtcs(void)
234 printf("id\tfb\tpos\tsize\n");
235 for (i = 0; i < resources->count_crtcs; i++) {
238 crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
240 fprintf(stderr, "could not get crtc %i: %s\n",
241 resources->crtcs[i], strerror(errno));
244 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
248 crtc->width, crtc->height);
249 dump_mode(&crtc->mode);
251 drmModeFreeCrtc(crtc);
257 static void dump_planes(void)
259 drmModePlaneRes *plane_resources;
263 plane_resources = drmModeGetPlaneResources(fd);
264 if (!plane_resources) {
265 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
271 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n");
272 for (i = 0; i < plane_resources->count_planes; i++) {
273 ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
275 fprintf(stderr, "drmModeGetPlane failed: %s\n",
280 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n",
281 ovr->plane_id, ovr->crtc_id, ovr->fb_id,
282 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
285 drmModeFreePlane(ovr);
292 static void dump_planes(void) { return; }
295 static void connector_find_preferred_mode(struct connector *c)
297 drmModeConnector *connector;
298 drmModeEncoder *encoder = NULL;
301 /* First, find the connector & mode */
303 connector = drmModeGetConnector(fd, c->id);
305 fprintf(stderr, "could not get connector %d: %s\n",
306 c->id, strerror(errno));
307 drmModeFreeConnector(connector);
311 if (connector->connection != DRM_MODE_CONNECTED) {
312 drmModeFreeConnector(connector);
316 if (!connector->count_modes) {
317 fprintf(stderr, "connector %d has no modes\n", c->id);
318 drmModeFreeConnector(connector);
322 if (connector->connector_id != c->id) {
323 fprintf(stderr, "connector id doesn't match (%d != %d)\n",
324 connector->connector_id, c->id);
325 drmModeFreeConnector(connector);
329 for (j = 0; j < connector->count_modes; j++) {
330 c->mode = connector->modes[j];
331 if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
337 if (!c->mode_valid) {
338 if (connector->count_modes > 0) {
339 /* use the first mode as test mode */
340 c->mode = connector->modes[0];
344 fprintf(stderr, "failed to find any modes on connector %d\n",
350 /* Now get the encoder */
351 for (i = 0; i < connector->count_encoders; i++) {
352 encoder = drmModeGetEncoder(fd, connector->encoders[i]);
355 fprintf(stderr, "could not get encoder %i: %s\n",
356 resources->encoders[i], strerror(errno));
357 drmModeFreeEncoder(encoder);
364 c->encoder = encoder;
366 if (i == resources->count_encoders) {
367 fprintf(stderr, "failed to find encoder\n");
372 /* Find first CRTC not in use */
373 for (i = 0; i < resources->count_crtcs; i++) {
374 if (resources->crtcs[i] && (c->encoder->possible_crtcs & (1<<i)))
377 c->crtc = resources->crtcs[i];
380 if(test_preferred_mode)
381 resources->crtcs[i] = 0;
383 c->connector = connector;
386 static uint32_t gem_create(int fd, int size)
388 struct drm_i915_gem_create create;
391 create.size = (size + 4095) & -4096;
392 (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
394 return create.handle;
397 static void *gem_mmap(int fd, uint32_t handle, int size, int prot)
399 struct drm_i915_gem_mmap_gtt mmap_arg;
402 mmap_arg.handle = handle;
403 if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
406 ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
407 if (ptr == MAP_FAILED)
413 static cairo_surface_t *
414 allocate_surface(int fd, int width, int height, uint32_t depth,
415 uint32_t *handle, int tiled)
417 cairo_format_t format;
418 struct drm_i915_gem_set_tiling set_tiling;
424 /* Round the tiling up to the next power-of-two and the
425 * region up to the next pot fence size so that this works
426 * on all generations.
428 * This can still fail if the framebuffer is too large to
429 * be tiled. But then that failure is expected.
433 for (stride = 512; stride < v; stride *= 2)
437 for (size = 1024*1024; size < v; size *= 2)
440 /* Scan-out has a 64 byte alignment restriction */
441 stride = (width * (bpp / 8) + 63) & ~63;
442 size = stride * height;
447 format = CAIRO_FORMAT_RGB16_565;
450 format = CAIRO_FORMAT_RGB24;
454 format = CAIRO_FORMAT_RGB30;
458 format = CAIRO_FORMAT_ARGB32;
461 fprintf(stderr, "bad depth %d\n", depth);
465 *handle = gem_create(fd, size);
468 set_tiling.handle = *handle;
469 set_tiling.tiling_mode = I915_TILING_X;
470 set_tiling.stride = stride;
471 if (ioctl(fd, DRM_IOCTL_I915_GEM_SET_TILING, &set_tiling)) {
472 fprintf(stderr, "set tiling failed: %s (stride=%d, size=%d)\n",
473 strerror(errno), stride, size);
478 fb_ptr = gem_mmap(fd, *handle, size, PROT_READ | PROT_WRITE);
480 return cairo_image_surface_create_for_data((unsigned char *)fb_ptr,
481 format, width, height,
493 paint_color_gradient(cairo_t *cr, int x, int y, int width, int height,
496 cairo_pattern_t *pat;
498 pat = cairo_pattern_create_linear(x, y, x + width, y + height);
499 cairo_pattern_add_color_stop_rgba(pat, 1, 0, 0, 0, 1);
500 cairo_pattern_add_color_stop_rgba(pat, 0, r, g, b, 1);
502 cairo_rectangle(cr, x, y, width, height);
503 cairo_set_source(cr, pat);
505 cairo_pattern_destroy(pat);
509 paint_color_key(void)
513 for (i = crtc_y; i < crtc_y + crtc_h; i++)
514 for (j = crtc_x; j < crtc_x + crtc_w; j++) {
517 offset = (i * width) + j;
518 fb_ptr[offset] = SPRITE_COLOR_KEY;
523 paint_test_patterns(cairo_t *cr, int width, int height, int stride)
525 double gr_height, gr_width;
529 gr_width = width * 0.75;
530 gr_height = height * 0.08;
531 x = (width / 2) - (gr_width / 2);
533 paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
536 paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
539 paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
542 paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
546 paint_marker(cairo_t *cr, int x, int y, char *str, enum corner text_location)
548 cairo_text_extents_t extents;
551 cairo_set_font_size(cr, 18);
552 cairo_text_extents(cr, str, &extents);
554 switch (text_location) {
557 xoff -= extents.width;
566 xoff -= extents.width;
578 cairo_move_to(cr, x, y - 20);
579 cairo_line_to(cr, x, y + 20);
580 cairo_move_to(cr, x - 20, y);
581 cairo_line_to(cr, x + 20, y);
582 cairo_new_sub_path(cr);
583 cairo_arc(cr, x, y, 10, 0, M_PI * 2);
584 cairo_set_line_width(cr, 4);
585 cairo_set_source_rgb(cr, 0, 0, 0);
586 cairo_stroke_preserve(cr);
587 cairo_set_source_rgb(cr, 1, 1, 1);
588 cairo_set_line_width(cr, 2);
591 cairo_move_to(cr, x + xoff, y + yoff);
592 cairo_text_path(cr, str);
593 cairo_set_source_rgb(cr, 0, 0, 0);
594 cairo_stroke_preserve(cr);
595 cairo_set_source_rgb(cr, 1, 1, 1);
600 paint_output_info(cairo_t *cr, struct connector *c, int width, int height)
602 cairo_text_extents_t name_extents, mode_extents;
603 char name_buf[128], mode_buf[128];
604 int i, x, y, modes_x, modes_y;
606 /* Get text extents for each string */
607 snprintf(name_buf, sizeof name_buf, "%s",
608 connector_type_str(c->connector->connector_type));
609 cairo_set_font_size(cr, 48);
610 cairo_select_font_face(cr, "Helvetica",
611 CAIRO_FONT_SLANT_NORMAL,
612 CAIRO_FONT_WEIGHT_NORMAL);
613 cairo_text_extents(cr, name_buf, &name_extents);
615 snprintf(mode_buf, sizeof mode_buf, "%s @ %dHz on %s encoder",
616 c->mode.name, c->mode.vrefresh,
617 encoder_type_str(c->encoder->encoder_type));
618 cairo_set_font_size(cr, 36);
619 cairo_text_extents(cr, mode_buf, &mode_extents);
621 /* Paint output name */
623 x -= name_extents.width / 2;
625 y -= (name_extents.height / 2) - (mode_extents.height / 2) - 10;
626 cairo_set_font_size(cr, 48);
627 cairo_move_to(cr, x, y);
628 cairo_text_path(cr, name_buf);
629 cairo_set_source_rgb(cr, 0, 0, 0);
630 cairo_stroke_preserve(cr);
631 cairo_set_source_rgb(cr, 1, 1, 1);
634 /* Paint mode name */
636 x -= mode_extents.width / 2;
639 y += (mode_extents.height / 2) + (name_extents.height / 2) + 10;
640 cairo_set_font_size(cr, 36);
641 cairo_move_to(cr, x, y);
642 cairo_text_path(cr, mode_buf);
643 cairo_set_source_rgb(cr, 0, 0, 0);
644 cairo_stroke_preserve(cr);
645 cairo_set_source_rgb(cr, 1, 1, 1);
648 /* List available modes */
649 snprintf(mode_buf, sizeof mode_buf, "Available modes:");
650 cairo_set_font_size(cr, 18);
651 cairo_text_extents(cr, mode_buf, &mode_extents);
653 modes_x = x + mode_extents.width;
654 y += mode_extents.height + 10;
656 cairo_move_to(cr, x, y);
657 cairo_text_path(cr, mode_buf);
658 cairo_set_source_rgb(cr, 0, 0, 0);
659 cairo_stroke_preserve(cr);
660 cairo_set_source_rgb(cr, 1, 1, 1);
663 for (i = 0; i < c->connector->count_modes; i++) {
664 snprintf(mode_buf, sizeof mode_buf, "%s @ %dHz",
665 c->connector->modes[i].name,
666 c->connector->modes[i].vrefresh);
667 cairo_set_font_size(cr, 18);
668 cairo_text_extents(cr, mode_buf, &mode_extents);
669 x = modes_x - mode_extents.width; /* right justify modes */
670 y += mode_extents.height + 10;
671 if (y + mode_extents.height >= height) {
672 y = modes_y + mode_extents.height + 10;
673 modes_x += mode_extents.width + 10;
674 x = modes_x - mode_extents.width;
676 cairo_move_to(cr, x, y);
677 cairo_text_path(cr, mode_buf);
678 cairo_set_source_rgb(cr, 0, 0, 0);
679 cairo_stroke_preserve(cr);
680 cairo_set_source_rgb(cr, 1, 1, 1);
687 connector_find_plane(struct connector *c)
689 drmModePlaneRes *plane_resources;
694 plane_resources = drmModeGetPlaneResources(fd);
695 if (!plane_resources) {
696 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
701 for (i = 0; i < plane_resources->count_planes; i++) {
702 ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
704 fprintf(stderr, "drmModeGetPlane failed: %s\n",
709 if (ovr->possible_crtcs & (1 << c->pipe)) {
711 drmModeFreePlane(ovr);
714 drmModeFreePlane(ovr);
721 paint_plane(cairo_t *cr, int width, int height, int stride)
723 double gr_height, gr_width;
728 gr_height = height * 0.25;
731 paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
734 paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
737 paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
740 paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
744 enable_plane(struct connector *c)
746 cairo_surface_t *surface;
747 cairo_status_t status;
751 uint32_t handles[4], pitches[4], offsets[4]; /* we only use [0] */
752 struct drm_intel_sprite_colorkey set;
753 uint32_t plane_flags = 0;
755 plane_id = connector_find_plane(c);
757 fprintf(stderr, "failed to find plane for crtc\n");
760 plane_crtc_id = c->crtc;
762 surface = allocate_surface(fd, plane_width, plane_height, 24, &handle, 1);
764 fprintf(stderr, "allocation failed %dx%d\n", plane_width, plane_height);
768 cr = cairo_create(surface);
770 paint_plane(cr, plane_width, plane_height,
771 cairo_image_surface_get_stride(surface));
772 status = cairo_status(cr);
775 fprintf(stderr, "failed to draw plane %dx%d: %s\n",
776 plane_width, plane_height, cairo_status_to_string(status));
778 pitches[0] = cairo_image_surface_get_stride(surface);
779 memset(offsets, 0, sizeof(offsets));
780 handles[0] = handles[1] = handles[2] = handles[3] = handle;
781 ret = drmModeAddFB2(fd, plane_width, plane_height, DRM_FORMAT_XRGB8888,
782 handles, pitches, offsets, &plane_fb_id,
784 cairo_surface_destroy(surface);
785 gem_close(fd, handle);
788 fprintf(stderr, "failed to add fb (%dx%d): %s\n",
789 plane_width, plane_height, strerror(errno));
793 set.plane_id = plane_id;
794 set.max_value = SPRITE_COLOR_KEY;
795 set.min_value = SPRITE_COLOR_KEY;
796 set.channel_mask = 0xffffff;
797 ret = drmCommandWrite(fd, DRM_I915_SET_SPRITE_COLORKEY, &set,
800 if (drmModeSetPlane(fd, plane_id, plane_crtc_id, plane_fb_id,
801 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
802 0, 0, plane_width, plane_height)) {
803 fprintf(stderr, "failed to enable plane: %s\n",
810 adjust_plane(int fd, int xdistance, int ydistance, int wdiff, int hdiff)
812 uint32_t plane_flags = 0;
818 fprintf(stderr, "setting plane %dx%d @ %d,%d (source %dx%d)\n",
819 crtc_w, crtc_h, crtc_x, crtc_y, plane_width, plane_height);
820 if (drmModeSetPlane(fd, plane_id, plane_crtc_id, plane_fb_id,
821 plane_flags, crtc_x, crtc_y,
822 crtc_w, crtc_h, 0, 0, plane_width, plane_height))
823 fprintf(stderr, "failed to adjust plane: %s\n", strerror(errno));
827 disable_planes(int fd)
829 struct connector *connectors;
832 resources = drmModeGetResources(fd);
834 fprintf(stderr, "drmModeGetResources failed: %s\n",
839 connectors = calloc(resources->count_connectors,
840 sizeof(struct connector));
844 /* Find any connected displays */
845 for (c = 0; c < resources->count_connectors; c++) {
848 plane_id = connector_find_plane(&connectors[c]);
851 "failed to find plane for crtc\n");
854 if (drmModeSetPlane(fd, plane_id, connectors[c].crtc, 0, 0, 0,
855 0, 0, 0, 0, 0, 0, 0)) {
856 fprintf(stderr, "failed to disable plane: %s\n",
861 drmModeFreeResources(resources);
865 static void enable_plane(struct connector *c) { return; }
867 adjust_plane(int fd, int xdistance, int ydistance, int wdiff, int hdiff)
869 static void disable_planes(int fd) { return; }
873 set_mode(struct connector *c)
878 int j, test_mode_num;
882 else if (depth > 8 && depth <= 16)
884 else if (depth > 16 && depth <= 32)
887 connector_find_preferred_mode(c);
893 c->mode.clock = force_clock*1000;
894 c->mode.hdisplay = force_hdisplay;
895 c->mode.hsync_start = force_hsync_start;
896 c->mode.hsync_end = force_hsync_end;
897 c->mode.htotal = force_htotal;
898 c->mode.vdisplay = force_vdisplay;
899 c->mode.vsync_start = force_vsync_start;
900 c->mode.vsync_end = force_vsync_end;
901 c->mode.vtotal = force_vtotal;
902 c->mode.vrefresh =(force_clock*1e6)/(force_htotal*force_vtotal);
904 sprintf(c->mode.name, "%dx%d", force_hdisplay, force_vdisplay);
905 } else if (test_all_modes)
906 test_mode_num = c->connector->count_modes;
908 for (j = 0; j < test_mode_num; j++) {
909 cairo_surface_t *surface;
910 cairo_status_t status;
915 c->mode = c->connector->modes[j];
920 width = c->mode.hdisplay;
921 height = c->mode.vdisplay;
923 surface = allocate_surface(fd, width, height, depth,
924 &handle, enable_tiling);
926 fprintf(stderr, "allocation failed %dx%d\n", width, height);
930 cr = cairo_create(surface);
932 paint_test_patterns(cr, width, height,
933 cairo_image_surface_get_stride(surface));
935 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
937 /* Paint corner markers */
938 snprintf(buf, sizeof buf, "(%d, %d)", 0, 0);
939 paint_marker(cr, 0, 0, buf, bottomright);
940 snprintf(buf, sizeof buf, "(%d, %d)", width, 0);
941 paint_marker(cr, width, 0, buf, bottomleft);
942 snprintf(buf, sizeof buf, "(%d, %d)", 0, height);
943 paint_marker(cr, 0, height, buf, topright);
944 snprintf(buf, sizeof buf, "(%d, %d)", width, height);
945 paint_marker(cr, width, height, buf, topleft);
947 /* Paint output info */
948 paint_output_info(cr, c, width, height);
952 status = cairo_status(cr);
955 fprintf(stderr, "failed to draw pretty picture %dx%d: %s\n",
956 width, height, cairo_status_to_string(status));
958 ret = drmModeAddFB(fd, width, height, depth, bpp,
959 cairo_image_surface_get_stride(surface),
961 cairo_surface_destroy(surface);
962 gem_close(fd, handle);
965 fprintf(stderr, "failed to add fb (%dx%d): %s\n",
966 width, height, strerror(errno));
970 fprintf(stdout, "CRTS(%u):",c->crtc);
972 if (drmModeSetCrtc(fd, c->crtc, fb_id, 0, 0,
973 &c->id, 1, &c->mode)) {
974 fprintf(stderr, "failed to set mode (%dx%d@%dHz): %s\n",
975 width, height, c->mode.vrefresh,
983 if (sleep_between_modes && test_all_modes)
984 sleep(sleep_between_modes);
988 if(!test_preferred_mode){
989 drmModeRmFB(fd,fb_id);
990 drmModeSetCrtc(fd, c->crtc, fb_id, 0, 0, &c->id, 1, 0);
993 drmModeFreeEncoder(c->encoder);
994 drmModeFreeConnector(c->connector);
998 * Re-probe outputs and light up as many as possible.
1000 * On Intel, we have two CRTCs that we can drive independently with
1001 * different timings and scanout buffers.
1003 * Each connector has a corresponding encoder, except in the SDVO case
1004 * where an encoder may have multiple connectors.
1006 static int update_display(void)
1008 struct connector *connectors;
1011 resources = drmModeGetResources(fd);
1013 fprintf(stderr, "drmModeGetResources failed: %s\n",
1018 connectors = calloc(resources->count_connectors,
1019 sizeof(struct connector));
1029 if (test_preferred_mode || test_all_modes || force_mode) {
1030 /* Find any connected displays */
1031 for (c = 0; c < resources->count_connectors; c++) {
1032 connectors[c].id = resources->connectors[c];
1033 set_mode(&connectors[c]);
1036 drmModeFreeResources(resources);
1040 static char optstr[] = "hiaf:s:d:p:mt";
1042 static void usage(char *name)
1044 fprintf(stderr, "usage: %s [-hiasdpmtf]\n", name);
1045 fprintf(stderr, "\t-i\tdump info\n");
1046 fprintf(stderr, "\t-a\ttest all modes\n");
1047 fprintf(stderr, "\t-s\t<duration>\tsleep between each mode test\n");
1048 fprintf(stderr, "\t-d\t<depth>\tbit depth of scanout buffer\n");
1049 fprintf(stderr, "\t-p\t<planew,h>,<crtcx,y>,<crtcw,h> test overlay plane\n");
1050 fprintf(stderr, "\t-m\ttest the preferred mode\n");
1051 fprintf(stderr, "\t-t\tuse a tiled framebuffer\n");
1052 fprintf(stderr, "\t-f\t<clock MHz>,<hdisp>,<hsync-start>,<hsync-end>,<htotal>,\n");
1053 fprintf(stderr, "\t\t<vdisp>,<vsync-start>,<vsync-end>,<vtotal>\n");
1054 fprintf(stderr, "\t\ttest force mode\n");
1055 fprintf(stderr, "\tDefault is to test all modes.\n");
1059 #define dump_resource(res) if (res) dump_##res()
1061 static gboolean hotplug_event(GIOChannel *source, GIOCondition condition,
1064 struct udev_device *dev;
1067 const char *hotplug;
1069 dev = udev_monitor_receive_device(uevent_monitor);
1073 udev_devnum = udev_device_get_devnum(dev);
1076 hotplug = udev_device_get_property_value(dev, "HOTPLUG");
1078 if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
1079 hotplug && atoi(hotplug) == 1)
1082 udev_device_unref(dev);
1087 static gboolean input_event(GIOChannel *source, GIOCondition condition,
1093 count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
1094 if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
1097 } else if (buf[0] == 'a')
1098 adjust_plane(fd, -10, 0, 0, 0);
1099 else if (buf[0] == 'd')
1100 adjust_plane(fd, 10, 0, 0, 0);
1101 else if (buf[0] == 'w')
1102 adjust_plane(fd, 0, -10, 0, 0);
1103 else if (buf[0] == 's')
1104 adjust_plane(fd, 0, 10, 0, 0);
1105 else if (buf[0] == 'j')
1106 adjust_plane(fd, 0, 0, 10, 0);
1107 else if (buf[0] == 'l')
1108 adjust_plane(fd, 0, 0, -10, 0);
1109 else if (buf[0] == 'k')
1110 adjust_plane(fd, 0, 0, 0, -10);
1111 else if (buf[0] == 'i')
1112 adjust_plane(fd, 0, 0, 0, 10);
1117 int main(int argc, char **argv)
1120 const char *modules[] = { "i915" };
1124 GIOChannel *udevchannel, *stdinchannel;
1125 GMainLoop *mainloop;
1128 while ((c = getopt(argc, argv, optstr)) != -1) {
1138 if(sscanf(optarg,"%f,%d,%d,%d,%d,%d,%d,%d,%d",
1139 &force_clock,&force_hdisplay, &force_hsync_start,&force_hsync_end,&force_htotal,
1140 &force_vdisplay, &force_vsync_start, &force_vsync_end, &force_vtotal)!= 9)
1144 sleep_between_modes = atoi(optarg);
1147 depth = atoi(optarg);
1148 fprintf(stderr, "using depth %d\n", depth);
1151 if (sscanf(optarg, "%d,%d,%d,%d,%d,%d", &plane_width,
1152 &plane_height, &crtc_x, &crtc_y,
1153 &crtc_w, &crtc_h) != 6)
1158 test_preferred_mode = 1;
1164 fprintf(stderr, "unknown option %c\n", c);
1171 if (!test_all_modes && !force_mode && !dump_info &&
1172 !test_preferred_mode)
1175 for (i = 0; i < ARRAY_SIZE(modules); i++) {
1176 fd = drmOpen(modules[i], NULL);
1178 printf("failed to load %s driver.\n", modules[i]);
1183 if (i == ARRAY_SIZE(modules)) {
1184 fprintf(stderr, "failed to load any modules, aborting.\n");
1191 fprintf(stderr, "failed to create udev object\n");
1196 uevent_monitor = udev_monitor_new_from_netlink(u, "udev");
1197 if (!uevent_monitor) {
1198 fprintf(stderr, "failed to create udev event monitor\n");
1200 goto out_udev_unref;
1203 ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
1207 fprintf(stderr, "failed to filter for drm events\n");
1208 goto out_udev_mon_unref;
1211 ret = udev_monitor_enable_receiving(uevent_monitor);
1213 fprintf(stderr, "failed to enable udev event reception\n");
1214 goto out_udev_mon_unref;
1217 mainloop = g_main_loop_new(NULL, FALSE);
1219 fprintf(stderr, "failed to create glib mainloop\n");
1221 goto out_mainloop_unref;
1225 g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor));
1227 fprintf(stderr, "failed to create udev GIO channel\n");
1228 goto out_mainloop_unref;
1231 ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event,
1234 fprintf(stderr, "failed to add watch on udev GIO channel\n");
1238 stdinchannel = g_io_channel_unix_new(0);
1239 if (!stdinchannel) {
1240 fprintf(stderr, "failed to create stdin GIO channel\n");
1244 ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
1247 fprintf(stderr, "failed to add watch on stdin GIO channel\n");
1253 if (!update_display()) {
1258 if (dump_info || test_all_modes)
1261 g_main_loop_run(mainloop);
1264 g_io_channel_shutdown(stdinchannel, TRUE, NULL);
1266 g_io_channel_shutdown(udevchannel, TRUE, NULL);
1268 g_main_loop_unref(mainloop);
1270 udev_monitor_unref(uevent_monitor);