testdisplay: fixup smaller compiler warnings
[platform/upstream/intel-gpu-tools.git] / tests / testdisplay.c
1 /*
2  * Copyright 2010 Intel Corporation
3  *   Jesse Barnes <jesse.barnes@intel.com>
4  *
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:
11  *
12  * The above copyright notice and this permission notice shall be included in
13  * all copies or substantial portions of the Software.
14  *
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
21  * IN THE SOFTWARE.
22  */
23
24 /*
25  * This program is intended for testing of display functionality.  It should
26  * allow for testing of
27  *   - hotplug
28  *   - mode setting
29  *   - clone & twin modes
30  *   - panel fitting
31  *   - test patterns & pixel generators
32  * Additional programs can test the detected outputs against VBT provided
33  * device lists (both docked & undocked).
34  *
35  * TODO:
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)
40  * - allow mode force
41  * - expose output specific controls
42  *  - e.g. DDC-CI brightness
43  *  - HDMI controls
44  *  - panel brightness
45  *  - DP commands (e.g. poweroff)
46  * - verify outputs against VBT/physical connectors
47  */
48 #include "config.h"
49
50 #include <assert.h>
51 #include <cairo.h>
52 #include <errno.h>
53 #include <glib.h>
54 #include <libudev.h>
55 #include <math.h>
56 #include <stdint.h>
57 #include <stdio.h>
58 #include <stdlib.h>
59 #include <string.h>
60 #include <unistd.h>
61 #include <sys/poll.h>
62 #include <sys/time.h>
63 #include <sys/mman.h>
64 #include <sys/ioctl.h>
65
66 #include "xf86drm.h"
67 #include "xf86drmMode.h"
68 #include "i915_drm.h"
69
70 #if defined(DRM_IOCTL_MODE_ADDFB2) && defined(DRM_I915_SET_SPRITE_COLORKEY)
71 #define TEST_PLANES 1
72 #include "drm_fourcc.h"
73 #endif
74
75 struct udev_monitor *uevent_monitor;
76 drmModeRes *resources;
77 int fd, modes;
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;
82
83 float force_clock;
84 int     force_hdisplay;
85 int     force_hsync_start;
86 int     force_hsync_end;
87 int     force_htotal;
88 int     force_vdisplay;
89 int     force_vsync_start;
90 int     force_vsync_end;
91 int     force_vtotal;
92
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;
99 uint32_t *fb_ptr;
100
101 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
102
103 struct type_name {
104         int type;
105         const char *name;
106 };
107
108 #define type_name_fn(res) \
109 static const char * res##_str(int type) {                       \
110         unsigned int i;                                 \
111         for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
112                 if (res##_names[i].type == type)        \
113                         return res##_names[i].name;     \
114         }                                               \
115         return "(invalid)";                             \
116 }
117
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" },
124 };
125
126 type_name_fn(encoder_type)
127
128 struct type_name connector_status_names[] = {
129         { DRM_MODE_CONNECTED, "connected" },
130         { DRM_MODE_DISCONNECTED, "disconnected" },
131         { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
132 };
133
134 type_name_fn(connector_status)
135
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" },
152 };
153
154 type_name_fn(connector_type)
155
156 /*
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.
162  */
163 struct connector {
164         uint32_t id;
165         int mode_valid;
166         drmModeModeInfo mode;
167         drmModeEncoder *encoder;
168         drmModeConnector *connector;
169         int crtc;
170         int pipe;
171 };
172
173 static void dump_mode(drmModeModeInfo *mode)
174 {
175         printf("  %s %d %d %d %d %d %d %d %d %d 0x%x 0x%x %d\n",
176                mode->name,
177                mode->vrefresh,
178                mode->hdisplay,
179                mode->hsync_start,
180                mode->hsync_end,
181                mode->htotal,
182                mode->vdisplay,
183                mode->vsync_start,
184                mode->vsync_end,
185                mode->vtotal,
186                mode->flags,
187                mode->type,
188                mode->clock);
189 }
190
191 static void dump_connectors(void)
192 {
193         int i, j;
194
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;
199
200                 connector = drmModeGetConnector(fd, resources->connectors[i]);
201                 if (!connector) {
202                         fprintf(stderr, "could not get connector %i: %s\n",
203                                 resources->connectors[i], strerror(errno));
204                         continue;
205                 }
206
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);
214
215                 if (!connector->count_modes)
216                         continue;
217
218                 printf("  modes:\n");
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]);
223
224                 drmModeFreeConnector(connector);
225         }
226         printf("\n");
227 }
228
229 static void dump_crtcs(void)
230 {
231         int i;
232
233         printf("CRTCs:\n");
234         printf("id\tfb\tpos\tsize\n");
235         for (i = 0; i < resources->count_crtcs; i++) {
236                 drmModeCrtc *crtc;
237
238                 crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
239                 if (!crtc) {
240                         fprintf(stderr, "could not get crtc %i: %s\n",
241                                 resources->crtcs[i], strerror(errno));
242                         continue;
243                 }
244                 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
245                        crtc->crtc_id,
246                        crtc->buffer_id,
247                        crtc->x, crtc->y,
248                        crtc->width, crtc->height);
249                 dump_mode(&crtc->mode);
250
251                 drmModeFreeCrtc(crtc);
252         }
253         printf("\n");
254 }
255
256 #ifdef TEST_PLANES
257 static void dump_planes(void)
258 {
259         drmModePlaneRes *plane_resources;
260         drmModePlane *ovr;
261         int i;
262
263         plane_resources = drmModeGetPlaneResources(fd);
264         if (!plane_resources) {
265                 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
266                         strerror(errno));
267                 return;
268         }
269
270         printf("Planes:\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]);
274                 if (!ovr) {
275                         fprintf(stderr, "drmModeGetPlane failed: %s\n",
276                                 strerror(errno));
277                         continue;
278                 }
279
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,
283                        ovr->gamma_size);
284
285                 drmModeFreePlane(ovr);
286         }
287         printf("\n");
288
289         return;
290 }
291 #else
292 static void dump_planes(void) { return; }
293 #endif
294
295 static void connector_find_preferred_mode(struct connector *c)
296 {
297         drmModeConnector *connector;
298         drmModeEncoder *encoder = NULL;
299         int i, j;
300
301         /* First, find the connector & mode */
302         c->mode_valid = 0;
303         connector = drmModeGetConnector(fd, c->id);
304         if (!connector) {
305                 fprintf(stderr, "could not get connector %d: %s\n",
306                         c->id, strerror(errno));
307                 drmModeFreeConnector(connector);
308                 return;
309         }
310
311         if (connector->connection != DRM_MODE_CONNECTED) {
312                 drmModeFreeConnector(connector);
313                 return;
314         }
315
316         if (!connector->count_modes) {
317                 fprintf(stderr, "connector %d has no modes\n", c->id);
318                 drmModeFreeConnector(connector);
319                 return;
320         }
321
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);
326                 return;
327         }
328
329         for (j = 0; j < connector->count_modes; j++) {
330                 c->mode = connector->modes[j];
331                 if (c->mode.type & DRM_MODE_TYPE_PREFERRED) {
332                         c->mode_valid = 1;
333                         break;
334                 }
335         }
336
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];
341                         c->mode_valid = 1;
342                 }
343                 else {
344                         fprintf(stderr, "failed to find any modes on connector %d\n",
345                                 c->id);
346                         return;
347                 }
348         }
349
350         /* Now get the encoder */
351         for (i = 0; i < connector->count_encoders; i++) {
352                 encoder = drmModeGetEncoder(fd, connector->encoders[i]);
353
354                 if (!encoder) {
355                         fprintf(stderr, "could not get encoder %i: %s\n",
356                                 resources->encoders[i], strerror(errno));
357                         drmModeFreeEncoder(encoder);
358                         continue;
359                 }
360
361                 break;
362         }
363
364         c->encoder = encoder;
365
366         if (i == resources->count_encoders) {
367                 fprintf(stderr, "failed to find encoder\n");
368                 c->mode_valid = 0;
369                 return;
370         }
371
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)))
375                         break;
376         }
377         c->crtc = resources->crtcs[i];
378         c->pipe = i;
379
380         if(test_preferred_mode)
381                 resources->crtcs[i] = 0;
382
383         c->connector = connector;
384 }
385
386 static uint32_t gem_create(int fd, int size)
387 {
388         struct drm_i915_gem_create create;
389
390         create.handle = 0;
391         create.size = (size + 4095) & -4096;
392         (void)drmIoctl(fd, DRM_IOCTL_I915_GEM_CREATE, &create);
393
394         return create.handle;
395 }
396
397 static void *gem_mmap(int fd, uint32_t handle, int size, int prot)
398 {
399         struct drm_i915_gem_mmap_gtt mmap_arg;
400         void *ptr;
401
402         mmap_arg.handle = handle;
403         if (drmIoctl(fd, DRM_IOCTL_I915_GEM_MMAP_GTT, &mmap_arg))
404                 return NULL;
405
406         ptr = mmap(0, size, prot, MAP_SHARED, fd, mmap_arg.offset);
407         if (ptr == MAP_FAILED)
408                 ptr = NULL;
409
410         return ptr;
411 }
412
413 static cairo_surface_t *
414 allocate_surface(int fd, int width, int height, uint32_t depth,
415                  uint32_t *handle, int tiled)
416 {
417         cairo_format_t format;
418         struct drm_i915_gem_set_tiling set_tiling;
419         int size;
420
421         if (tiled) {
422                 int v;
423
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.
427                  *
428                  * This can still fail if the framebuffer is too large to
429                  * be tiled. But then that failure is expected.
430                  */
431
432                 v = width * bpp / 8;
433                 for (stride = 512; stride < v; stride *= 2)
434                         ;
435
436                 v = stride * height;
437                 for (size = 1024*1024; size < v; size *= 2)
438                         ;
439         } else {
440                 /* Scan-out has a 64 byte alignment restriction */
441                 stride = (width * (bpp / 8) + 63) & ~63;
442                 size = stride * height;
443         }
444
445         switch (depth) {
446         case 16:
447                 format = CAIRO_FORMAT_RGB16_565;
448                 break;
449         case 24:
450                 format = CAIRO_FORMAT_RGB24;
451                 break;
452 #if 0
453         case 30:
454                 format = CAIRO_FORMAT_RGB30;
455                 break;
456 #endif
457         case 32:
458                 format = CAIRO_FORMAT_ARGB32;
459                 break;
460         default:
461                 fprintf(stderr, "bad depth %d\n", depth);
462                 return NULL;
463         }
464
465         *handle = gem_create(fd, size);
466
467         if (tiled) {
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);
474                         return NULL;
475                 }
476         }
477
478         fb_ptr = gem_mmap(fd, *handle, size, PROT_READ | PROT_WRITE);
479
480         return cairo_image_surface_create_for_data((unsigned char *)fb_ptr,
481                                                    format, width, height,
482                                                    stride);
483 }
484
485 enum corner {
486         topleft,
487         topright,
488         bottomleft,
489         bottomright,
490 };
491
492 static void
493 paint_color_gradient(cairo_t *cr, int x, int y, int width, int height,
494                      int r, int g, int b)
495 {
496         cairo_pattern_t *pat;
497
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);
501
502         cairo_rectangle(cr, x, y, width, height);
503         cairo_set_source(cr, pat);
504         cairo_fill(cr);
505         cairo_pattern_destroy(pat);
506 }
507
508 static void
509 paint_color_key(void)
510 {
511         int i, j;
512
513         for (i = crtc_y; i < crtc_y + crtc_h; i++)
514                 for (j = crtc_x; j < crtc_x + crtc_w; j++) {
515                         uint32_t offset;
516
517                         offset = (i * width) + j;
518                         fb_ptr[offset] = SPRITE_COLOR_KEY;
519                 }
520 }
521
522 static void
523 paint_test_patterns(cairo_t *cr, int width, int height, int stride)
524 {
525         double gr_height, gr_width;
526         int x, y;
527
528         y = height * 0.10;
529         gr_width = width * 0.75;
530         gr_height = height * 0.08;
531         x = (width / 2) - (gr_width / 2);
532
533         paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
534
535         y += gr_height;
536         paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
537
538         y += gr_height;
539         paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
540
541         y += gr_height;
542         paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
543 }
544
545 static void
546 paint_marker(cairo_t *cr, int x, int y, char *str, enum corner text_location)
547 {
548         cairo_text_extents_t extents;
549         int xoff, yoff;
550
551         cairo_set_font_size(cr, 18);
552         cairo_text_extents(cr, str, &extents);
553
554         switch (text_location) {
555         case topleft:
556                 xoff = -20;
557                 xoff -= extents.width;
558                 yoff = -20;
559                 break;
560         case topright:
561                 xoff = 20;
562                 yoff = -20;
563                 break;
564         case bottomleft:
565                 xoff = -20;
566                 xoff -= extents.width;
567                 yoff = 20;
568                 break;
569         case bottomright:
570                 xoff = 20;
571                 yoff = 20;
572                 break;
573         default:
574                 xoff = 0;
575                 yoff = 0;
576         }
577
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);
589         cairo_stroke(cr);
590
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);
596         cairo_fill(cr);
597 }
598
599 static void
600 paint_output_info(cairo_t *cr, struct connector *c, int width, int height)
601 {
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;
605
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);
614
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);
620
621         /* Paint output name */
622         x = width / 2;
623         x -= name_extents.width / 2;
624         y = height / 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);
632         cairo_fill(cr);
633
634         /* Paint mode name */
635         x = width / 2;
636         x -= mode_extents.width / 2;
637         modes_x = x;
638         y = height / 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);
646         cairo_fill(cr);
647
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);
652         x = modes_x;
653         modes_x = x + mode_extents.width;
654         y += mode_extents.height + 10;
655         modes_y = y;
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);
661         cairo_fill(cr);
662
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;
675                 }
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);
681                 cairo_fill(cr);
682         }
683 }
684
685 #ifdef TEST_PLANES
686 static int
687 connector_find_plane(struct connector *c)
688 {
689         drmModePlaneRes *plane_resources;
690         drmModePlane *ovr;
691         uint32_t id = 0;
692         int i;
693
694         plane_resources = drmModeGetPlaneResources(fd);
695         if (!plane_resources) {
696                 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
697                         strerror(errno));
698                 return 0;
699         }
700
701         for (i = 0; i < plane_resources->count_planes; i++) {
702                 ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
703                 if (!ovr) {
704                         fprintf(stderr, "drmModeGetPlane failed: %s\n",
705                                 strerror(errno));
706                         continue;
707                 }
708
709                 if (ovr->possible_crtcs & (1 << c->pipe)) {
710                         id = ovr->plane_id;
711                         drmModeFreePlane(ovr);
712                         break;
713                 }
714                 drmModeFreePlane(ovr);
715         }
716
717         return id;
718 }
719
720 static void
721 paint_plane(cairo_t *cr, int width, int height, int stride)
722 {
723         double gr_height, gr_width;
724         int x, y;
725
726         y = 0;
727         gr_width = width;
728         gr_height = height * 0.25;
729         x = 0;
730
731         paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 0, 0);
732
733         y += gr_height;
734         paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 1, 0);
735
736         y += gr_height;
737         paint_color_gradient(cr, x, y, gr_width, gr_height, 0, 0, 1);
738
739         y += gr_height;
740         paint_color_gradient(cr, x, y, gr_width, gr_height, 1, 1, 1);
741 }
742
743 static void
744 enable_plane(struct connector *c)
745 {
746         cairo_surface_t *surface;
747         cairo_status_t status;
748         cairo_t *cr;
749         uint32_t handle;
750         int ret;
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;
754
755         plane_id = connector_find_plane(c);
756         if (!plane_id) {
757                 fprintf(stderr, "failed to find plane for crtc\n");
758                 return;
759         }
760         plane_crtc_id = c->crtc;
761
762         surface = allocate_surface(fd, plane_width, plane_height, 24, &handle, 1);
763         if (!surface) {
764                 fprintf(stderr, "allocation failed %dx%d\n", plane_width, plane_height);
765                 return;
766         }
767
768         cr = cairo_create(surface);
769
770         paint_plane(cr, plane_width, plane_height,
771                       cairo_image_surface_get_stride(surface));
772         status = cairo_status(cr);
773         cairo_destroy(cr);
774         if (status)
775                 fprintf(stderr, "failed to draw plane %dx%d: %s\n",
776                         plane_width, plane_height, cairo_status_to_string(status));
777
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,
783                             plane_flags);
784         cairo_surface_destroy(surface);
785         gem_close(fd, handle);
786
787         if (ret) {
788                 fprintf(stderr, "failed to add fb (%dx%d): %s\n",
789                         plane_width, plane_height, strerror(errno));
790                 return;
791         }
792
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,
798                               sizeof(set));
799
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",
804                         strerror(errno));
805                 return;
806         }
807 }
808
809 static void
810 adjust_plane(int fd, int xdistance, int ydistance, int wdiff, int hdiff)
811 {
812         uint32_t plane_flags = 0;
813
814         crtc_x += xdistance;
815         crtc_y += ydistance;
816         crtc_w += wdiff;
817         crtc_h += hdiff;
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));
824 }
825
826 static void
827 disable_planes(int fd)
828 {
829         struct connector *connectors;
830         int c;
831
832         resources = drmModeGetResources(fd);
833         if (!resources) {
834                 fprintf(stderr, "drmModeGetResources failed: %s\n",
835                         strerror(errno));
836                 return;
837         }
838
839         connectors = calloc(resources->count_connectors,
840                             sizeof(struct connector));
841         if (!connectors)
842                 return;
843
844         /* Find any connected displays */
845         for (c = 0; c < resources->count_connectors; c++) {
846                 uint32_t plane_id;
847
848                 plane_id = connector_find_plane(&connectors[c]);
849                 if (!plane_id) {
850                         fprintf(stderr,
851                                 "failed to find plane for crtc\n");
852                         return;
853                 }
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",
857                                 strerror(errno));
858                         return;
859                 }
860         }
861         drmModeFreeResources(resources);
862         return;
863 }
864 #else
865 static void enable_plane(struct connector *c) { return; }
866 static void
867 adjust_plane(int fd, int xdistance, int ydistance, int wdiff, int hdiff)
868 { return; }
869 static void disable_planes(int fd) { return; }
870 #endif
871
872 static void
873 set_mode(struct connector *c)
874 {
875         unsigned int fb_id;
876         int ret;
877         char buf[128];
878         int j, test_mode_num;
879
880         if (depth <= 8)
881                 bpp = 8;
882         else if (depth > 8 && depth <= 16)
883                 bpp = 16;
884         else if (depth > 16 && depth <= 32)
885                 bpp = 32;
886
887         connector_find_preferred_mode(c);
888         if (!c->mode_valid)
889                 return;
890
891         test_mode_num = 1;
892         if (force_mode){
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);
903                 c->mode_valid = 1;
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;
907
908         for (j = 0; j < test_mode_num; j++) {
909                 cairo_surface_t *surface;
910                 cairo_status_t status;
911                 cairo_t *cr;
912                 uint32_t handle;
913
914                 if (test_all_modes)
915                         c->mode = c->connector->modes[j];
916
917                 if (!c->mode_valid)
918                         continue;
919
920                 width = c->mode.hdisplay;
921                 height = c->mode.vdisplay;
922
923                 surface = allocate_surface(fd, width, height, depth,
924                                            &handle, enable_tiling);
925                 if (!surface) {
926                         fprintf(stderr, "allocation failed %dx%d\n", width, height);
927                         continue;
928                 }
929
930                 cr = cairo_create(surface);
931
932                 paint_test_patterns(cr, width, height,
933                                     cairo_image_surface_get_stride(surface));
934
935                 cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
936
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);
946
947                 /* Paint output info */
948                 paint_output_info(cr, c, width, height);
949
950                 paint_color_key();
951
952                 status = cairo_status(cr);
953                 cairo_destroy(cr);
954                 if (status)
955                         fprintf(stderr, "failed to draw pretty picture %dx%d: %s\n",
956                                 width, height, cairo_status_to_string(status));
957
958                 ret = drmModeAddFB(fd, width, height, depth, bpp,
959                                    cairo_image_surface_get_stride(surface),
960                                    handle, &fb_id);
961                 cairo_surface_destroy(surface);
962                 gem_close(fd, handle);
963
964                 if (ret) {
965                         fprintf(stderr, "failed to add fb (%dx%d): %s\n",
966                                 width, height, strerror(errno));
967                         continue;
968                 }
969
970                 fprintf(stdout, "CRTS(%u):",c->crtc);
971                 dump_mode(&c->mode);
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,
976                                 strerror(errno));
977                         continue;
978                 }
979
980                 if (test_plane)
981                         enable_plane(c);
982
983                 if (sleep_between_modes && test_all_modes)
984                         sleep(sleep_between_modes);
985
986         }
987
988         if(!test_preferred_mode){
989                 drmModeRmFB(fd,fb_id);
990                 drmModeSetCrtc(fd, c->crtc, fb_id, 0, 0,  &c->id, 1, 0);
991         }
992
993         drmModeFreeEncoder(c->encoder);
994         drmModeFreeConnector(c->connector);
995 }
996
997 /*
998  * Re-probe outputs and light up as many as possible.
999  *
1000  * On Intel, we have two CRTCs that we can drive independently with
1001  * different timings and scanout buffers.
1002  *
1003  * Each connector has a corresponding encoder, except in the SDVO case
1004  * where an encoder may have multiple connectors.
1005  */
1006 static int update_display(void)
1007 {
1008         struct connector *connectors;
1009         int c;
1010
1011         resources = drmModeGetResources(fd);
1012         if (!resources) {
1013                 fprintf(stderr, "drmModeGetResources failed: %s\n",
1014                         strerror(errno));
1015                 return 0;
1016         }
1017
1018         connectors = calloc(resources->count_connectors,
1019                             sizeof(struct connector));
1020         if (!connectors)
1021                 return 0;
1022
1023         if (dump_info) {
1024                 dump_connectors();
1025                 dump_crtcs();
1026                 dump_planes();
1027         }
1028
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]);
1034                 }
1035         }
1036         drmModeFreeResources(resources);
1037         return 1;
1038 }
1039
1040 static char optstr[] = "hiaf:s:d:p:mt";
1041
1042 static void usage(char *name)
1043 {
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");
1056         exit(0);
1057 }
1058
1059 #define dump_resource(res) if (res) dump_##res()
1060
1061 static gboolean hotplug_event(GIOChannel *source, GIOCondition condition,
1062                               gpointer data)
1063 {
1064         struct udev_device *dev;
1065         dev_t udev_devnum;
1066         struct stat s;
1067         const char *hotplug;
1068
1069         dev = udev_monitor_receive_device(uevent_monitor);
1070         if (!dev)
1071                 goto out;
1072
1073         udev_devnum = udev_device_get_devnum(dev);
1074         fstat(fd, &s);
1075
1076         hotplug = udev_device_get_property_value(dev, "HOTPLUG");
1077
1078         if (memcmp(&s.st_rdev, &udev_devnum, sizeof(dev_t)) == 0 &&
1079             hotplug && atoi(hotplug) == 1)
1080                 update_display();
1081
1082         udev_device_unref(dev);
1083 out:
1084         return TRUE;
1085 }
1086
1087 static gboolean input_event(GIOChannel *source, GIOCondition condition,
1088                             gpointer data)
1089 {
1090         gchar buf[2];
1091         gsize count;
1092
1093         count = read(g_io_channel_unix_get_fd(source), buf, sizeof(buf));
1094         if (buf[0] == 'q' && (count == 1 || buf[1] == '\n')) {
1095                 disable_planes(fd);
1096                 exit(0);
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);
1113
1114         return TRUE;
1115 }
1116
1117 int main(int argc, char **argv)
1118 {
1119         int c;
1120         const char *modules[] = { "i915" };
1121         unsigned int i;
1122         struct udev *u;
1123         int ret = 0;
1124         GIOChannel *udevchannel, *stdinchannel;
1125         GMainLoop *mainloop;
1126
1127         opterr = 0;
1128         while ((c = getopt(argc, argv, optstr)) != -1) {
1129                 switch (c) {
1130                 case 'i':
1131                         dump_info = 1;
1132                         break;
1133                 case 'a':
1134                         test_all_modes = 1;
1135                         break;
1136                 case 'f':
1137                         force_mode = 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)
1141                                 usage(argv[0]);
1142                         break;
1143                 case 's':
1144                         sleep_between_modes = atoi(optarg);
1145                         break;
1146                 case 'd':
1147                         depth = atoi(optarg);
1148                         fprintf(stderr, "using depth %d\n", depth);
1149                         break;
1150                 case 'p':
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)
1154                                 usage(argv[0]);
1155                         test_plane = 1;
1156                         break;
1157                 case 'm':
1158                         test_preferred_mode = 1;
1159                         break;
1160                 case 't':
1161                         enable_tiling = 1;
1162                         break;
1163                 default:
1164                         fprintf(stderr, "unknown option %c\n", c);
1165                         /* fall through */
1166                 case 'h':
1167                         usage(argv[0]);
1168                         break;
1169                 }
1170         }
1171         if (!test_all_modes && !force_mode && !dump_info &&
1172             !test_preferred_mode)
1173                 test_all_modes = 1;
1174
1175         for (i = 0; i < ARRAY_SIZE(modules); i++) {
1176                 fd = drmOpen(modules[i], NULL);
1177                 if (fd < 0)
1178                         printf("failed to load %s driver.\n", modules[i]);
1179                 else
1180                         break;
1181         }
1182
1183         if (i == ARRAY_SIZE(modules)) {
1184                 fprintf(stderr, "failed to load any modules, aborting.\n");
1185                 ret = -1;
1186                 goto out;
1187         }
1188
1189         u = udev_new();
1190         if (!u) {
1191                 fprintf(stderr, "failed to create udev object\n");
1192                 ret = -1;
1193                 goto out_close;
1194         }
1195
1196         uevent_monitor = udev_monitor_new_from_netlink(u, "udev");
1197         if (!uevent_monitor) {
1198                 fprintf(stderr, "failed to create udev event monitor\n");
1199                 ret = -1;
1200                 goto out_udev_unref;
1201         }
1202
1203         ret = udev_monitor_filter_add_match_subsystem_devtype(uevent_monitor,
1204                                                               "drm",
1205                                                               "drm_minor");
1206         if (ret < 0) {
1207                 fprintf(stderr, "failed to filter for drm events\n");
1208                 goto out_udev_mon_unref;
1209         }
1210
1211         ret = udev_monitor_enable_receiving(uevent_monitor);
1212         if (ret < 0) {
1213                 fprintf(stderr, "failed to enable udev event reception\n");
1214                 goto out_udev_mon_unref;
1215         }
1216
1217         mainloop = g_main_loop_new(NULL, FALSE);
1218         if (!mainloop) {
1219                 fprintf(stderr, "failed to create glib mainloop\n");
1220                 ret = -1;
1221                 goto out_mainloop_unref;
1222         }
1223
1224         udevchannel =
1225                 g_io_channel_unix_new(udev_monitor_get_fd(uevent_monitor));
1226         if (!udevchannel) {
1227                 fprintf(stderr, "failed to create udev GIO channel\n");
1228                 goto out_mainloop_unref;
1229         }
1230
1231         ret = g_io_add_watch(udevchannel, G_IO_IN | G_IO_ERR, hotplug_event,
1232                              u);
1233         if (ret < 0) {
1234                 fprintf(stderr, "failed to add watch on udev GIO channel\n");
1235                 goto out_udev_off;
1236         }
1237
1238         stdinchannel = g_io_channel_unix_new(0);
1239         if (!stdinchannel) {
1240                 fprintf(stderr, "failed to create stdin GIO channel\n");
1241                 goto out_udev_off;
1242         }
1243
1244         ret = g_io_add_watch(stdinchannel, G_IO_IN | G_IO_ERR, input_event,
1245                              NULL);
1246         if (ret < 0) {
1247                 fprintf(stderr, "failed to add watch on stdin GIO channel\n");
1248                 goto out_stdio_off;
1249         }
1250
1251         ret = 0;
1252
1253         if (!update_display()) {
1254                 ret = 1;
1255                 goto out_stdio_off;
1256         }
1257
1258         if (dump_info || test_all_modes)
1259                 goto out_stdio_off;
1260
1261         g_main_loop_run(mainloop);
1262
1263 out_stdio_off:
1264         g_io_channel_shutdown(stdinchannel, TRUE, NULL);
1265 out_udev_off:
1266         g_io_channel_shutdown(udevchannel, TRUE, NULL);
1267 out_mainloop_unref:
1268         g_main_loop_unref(mainloop);
1269 out_udev_mon_unref:
1270         udev_monitor_unref(uevent_monitor);
1271 out_udev_unref:
1272         udev_unref(u);
1273 out_close:
1274         if (test_plane)
1275                 disable_planes(fd);
1276         drmClose(fd);
1277 out:
1278         return ret;
1279 }