OSDN Git Service

modetest: Make frame buffer format configurable on the command line
[android-x86/external-libdrm.git] / tests / modetest / modetest.c
1 /*
2  * DRM based mode setting test program
3  * Copyright 2008 Tungsten Graphics
4  *   Jakob Bornecrantz <jakob@tungstengraphics.com>
5  * Copyright 2008 Intel Corporation
6  *   Jesse Barnes <jesse.barnes@intel.com>
7  *
8  * Permission is hereby granted, free of charge, to any person obtaining a
9  * copy of this software and associated documentation files (the "Software"),
10  * to deal in the Software without restriction, including without limitation
11  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
12  * and/or sell copies of the Software, and to permit persons to whom the
13  * Software is furnished to do so, subject to the following conditions:
14  *
15  * The above copyright notice and this permission notice shall be included in
16  * all copies or substantial portions of the Software.
17  *
18  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
23  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
24  * IN THE SOFTWARE.
25  */
26
27 /*
28  * This fairly simple test program dumps output in a similar format to the
29  * "xrandr" tool everyone knows & loves.  It's necessarily slightly different
30  * since the kernel separates outputs into encoder and connector structures,
31  * each with their own unique ID.  The program also allows test testing of the
32  * memory management and mode setting APIs by allowing the user to specify a
33  * connector and mode to use for mode setting.  If all works as expected, a
34  * blue background should be painted on the monitor attached to the specified
35  * connector after the selected mode is set.
36  *
37  * TODO: use cairo to write the mode info on the selected output once
38  *       the mode has been programmed, along with possible test patterns.
39  */
40 #include "config.h"
41
42 #include <assert.h>
43 #include <stdio.h>
44 #include <stdlib.h>
45 #include <stdint.h>
46 #include <inttypes.h>
47 #include <unistd.h>
48 #include <string.h>
49 #include <errno.h>
50 #include <sys/poll.h>
51 #include <sys/time.h>
52
53 #include "xf86drm.h"
54 #include "xf86drmMode.h"
55 #include "drm_fourcc.h"
56 #include "libkms.h"
57
58 #ifdef HAVE_CAIRO
59 #include <math.h>
60 #include <cairo.h>
61 #endif
62
63 drmModeRes *resources;
64 int fd, modes;
65
66 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
67
68 struct type_name {
69         int type;
70         char *name;
71 };
72
73 #define type_name_fn(res) \
74 char * res##_str(int type) {                    \
75         unsigned int i;                                 \
76         for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
77                 if (res##_names[i].type == type)        \
78                         return res##_names[i].name;     \
79         }                                               \
80         return "(invalid)";                             \
81 }
82
83 struct type_name encoder_type_names[] = {
84         { DRM_MODE_ENCODER_NONE, "none" },
85         { DRM_MODE_ENCODER_DAC, "DAC" },
86         { DRM_MODE_ENCODER_TMDS, "TMDS" },
87         { DRM_MODE_ENCODER_LVDS, "LVDS" },
88         { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
89 };
90
91 type_name_fn(encoder_type)
92
93 struct type_name connector_status_names[] = {
94         { DRM_MODE_CONNECTED, "connected" },
95         { DRM_MODE_DISCONNECTED, "disconnected" },
96         { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
97 };
98
99 type_name_fn(connector_status)
100
101 struct type_name connector_type_names[] = {
102         { DRM_MODE_CONNECTOR_Unknown, "unknown" },
103         { DRM_MODE_CONNECTOR_VGA, "VGA" },
104         { DRM_MODE_CONNECTOR_DVII, "DVI-I" },
105         { DRM_MODE_CONNECTOR_DVID, "DVI-D" },
106         { DRM_MODE_CONNECTOR_DVIA, "DVI-A" },
107         { DRM_MODE_CONNECTOR_Composite, "composite" },
108         { DRM_MODE_CONNECTOR_SVIDEO, "s-video" },
109         { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
110         { DRM_MODE_CONNECTOR_Component, "component" },
111         { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
112         { DRM_MODE_CONNECTOR_DisplayPort, "displayport" },
113         { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
114         { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
115         { DRM_MODE_CONNECTOR_TV, "TV" },
116         { DRM_MODE_CONNECTOR_eDP, "embedded displayport" },
117 };
118
119 type_name_fn(connector_type)
120
121 #define bit_name_fn(res)                                        \
122 char * res##_str(int type) {                                    \
123         int i;                                                  \
124         const char *sep = "";                                   \
125         for (i = 0; i < ARRAY_SIZE(res##_names); i++) {         \
126                 if (type & (1 << i)) {                          \
127                         printf("%s%s", sep, res##_names[i]);    \
128                         sep = ", ";                             \
129                 }                                               \
130         }                                                       \
131 }
132
133 static const char *mode_type_names[] = {
134         "builtin",
135         "clock_c",
136         "crtc_c",
137         "preferred",
138         "default",
139         "userdef",
140         "driver",
141 };
142
143 bit_name_fn(mode_type)
144
145 static const char *mode_flag_names[] = {
146         "phsync",
147         "nhsync",
148         "pvsync",
149         "nvsync",
150         "interlace",
151         "dblscan",
152         "csync",
153         "pcsync",
154         "ncsync",
155         "hskew",
156         "bcast",
157         "pixmux",
158         "dblclk",
159         "clkdiv2"
160 };
161
162 bit_name_fn(mode_flag)
163
164 void dump_encoders(void)
165 {
166         drmModeEncoder *encoder;
167         int i;
168
169         printf("Encoders:\n");
170         printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
171         for (i = 0; i < resources->count_encoders; i++) {
172                 encoder = drmModeGetEncoder(fd, resources->encoders[i]);
173
174                 if (!encoder) {
175                         fprintf(stderr, "could not get encoder %i: %s\n",
176                                 resources->encoders[i], strerror(errno));
177                         continue;
178                 }
179                 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
180                        encoder->encoder_id,
181                        encoder->crtc_id,
182                        encoder_type_str(encoder->encoder_type),
183                        encoder->possible_crtcs,
184                        encoder->possible_clones);
185                 drmModeFreeEncoder(encoder);
186         }
187         printf("\n");
188 }
189
190 void dump_mode(drmModeModeInfo *mode)
191 {
192         printf("  %s %d %d %d %d %d %d %d %d %d",
193                mode->name,
194                mode->vrefresh,
195                mode->hdisplay,
196                mode->hsync_start,
197                mode->hsync_end,
198                mode->htotal,
199                mode->vdisplay,
200                mode->vsync_start,
201                mode->vsync_end,
202                mode->vtotal);
203
204         printf(" flags: ");
205         mode_flag_str(mode->flags);
206         printf("; type: ");
207         mode_type_str(mode->type);
208         printf("\n");
209 }
210
211 static void
212 dump_blob(uint32_t blob_id)
213 {
214         uint32_t i;
215         unsigned char *blob_data;
216         drmModePropertyBlobPtr blob;
217
218         blob = drmModeGetPropertyBlob(fd, blob_id);
219         if (!blob)
220                 return;
221
222         blob_data = blob->data;
223
224         for (i = 0; i < blob->length; i++) {
225                 if (i % 16 == 0)
226                         printf("\n\t\t\t");
227                 printf("%.2hhx", blob_data[i]);
228         }
229         printf("\n");
230
231         drmModeFreePropertyBlob(blob);
232 }
233
234 static void
235 dump_prop(uint32_t prop_id, uint64_t value)
236 {
237         int i;
238         drmModePropertyPtr prop;
239
240         prop = drmModeGetProperty(fd, prop_id);
241
242         printf("\t%d", prop_id);
243         if (!prop) {
244                 printf("\n");
245                 return;
246         }
247
248         printf(" %s:\n", prop->name);
249
250         printf("\t\tflags:");
251         if (prop->flags & DRM_MODE_PROP_PENDING)
252                 printf(" pending");
253         if (prop->flags & DRM_MODE_PROP_RANGE)
254                 printf(" range");
255         if (prop->flags & DRM_MODE_PROP_IMMUTABLE)
256                 printf(" immutable");
257         if (prop->flags & DRM_MODE_PROP_ENUM)
258                 printf(" enum");
259         if (prop->flags & DRM_MODE_PROP_BITMASK)
260                 printf(" bitmask");
261         if (prop->flags & DRM_MODE_PROP_BLOB)
262                 printf(" blob");
263         printf("\n");
264
265         if (prop->flags & DRM_MODE_PROP_RANGE) {
266                 printf("\t\tvalues:");
267                 for (i = 0; i < prop->count_values; i++)
268                         printf(" %"PRIu64, prop->values[i]);
269                 printf("\n");
270         }
271
272         if (prop->flags & DRM_MODE_PROP_ENUM) {
273                 printf("\t\tenums:");
274                 for (i = 0; i < prop->count_enums; i++)
275                         printf(" %s=%llu", prop->enums[i].name,
276                                prop->enums[i].value);
277                 printf("\n");
278         } else if (prop->flags & DRM_MODE_PROP_BITMASK) {
279                 printf("\t\tvalues:");
280                 for (i = 0; i < prop->count_enums; i++)
281                         printf(" %s=0x%llx", prop->enums[i].name,
282                                (1LL << prop->enums[i].value));
283                 printf("\n");
284         } else {
285                 assert(prop->count_enums == 0);
286         }
287
288         if (prop->flags & DRM_MODE_PROP_BLOB) {
289                 printf("\t\tblobs:\n");
290                 for (i = 0; i < prop->count_blobs; i++)
291                         dump_blob(prop->blob_ids[i]);
292                 printf("\n");
293         } else {
294                 assert(prop->count_blobs == 0);
295         }
296
297         printf("\t\tvalue:");
298         if (prop->flags & DRM_MODE_PROP_BLOB)
299                 dump_blob(value);
300         else
301                 printf(" %"PRIu64"\n", value);
302
303         drmModeFreeProperty(prop);
304 }
305
306 void dump_connectors(void)
307 {
308         drmModeConnector *connector;
309         int i, j;
310
311         printf("Connectors:\n");
312         printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n");
313         for (i = 0; i < resources->count_connectors; i++) {
314                 connector = drmModeGetConnector(fd, resources->connectors[i]);
315
316                 if (!connector) {
317                         fprintf(stderr, "could not get connector %i: %s\n",
318                                 resources->connectors[i], strerror(errno));
319                         continue;
320                 }
321
322                 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t",
323                        connector->connector_id,
324                        connector->encoder_id,
325                        connector_status_str(connector->connection),
326                        connector_type_str(connector->connector_type),
327                        connector->mmWidth, connector->mmHeight,
328                        connector->count_modes);
329
330                 for (j = 0; j < connector->count_encoders; j++)
331                         printf("%s%d", j > 0 ? ", " : "", connector->encoders[j]);
332                 printf("\n");
333
334                 if (connector->count_modes) {
335                         printf("  modes:\n");
336                         printf("\tname refresh (Hz) hdisp hss hse htot vdisp "
337                                "vss vse vtot)\n");
338                         for (j = 0; j < connector->count_modes; j++)
339                                 dump_mode(&connector->modes[j]);
340
341                         printf("  props:\n");
342                         for (j = 0; j < connector->count_props; j++)
343                                 dump_prop(connector->props[j],
344                                           connector->prop_values[j]);
345                 }
346
347                 drmModeFreeConnector(connector);
348         }
349         printf("\n");
350 }
351
352 void dump_crtcs(void)
353 {
354         drmModeCrtc *crtc;
355         drmModeObjectPropertiesPtr props;
356         int i;
357         uint32_t j;
358
359         printf("CRTCs:\n");
360         printf("id\tfb\tpos\tsize\n");
361         for (i = 0; i < resources->count_crtcs; i++) {
362                 crtc = drmModeGetCrtc(fd, resources->crtcs[i]);
363
364                 if (!crtc) {
365                         fprintf(stderr, "could not get crtc %i: %s\n",
366                                 resources->crtcs[i], strerror(errno));
367                         continue;
368                 }
369                 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
370                        crtc->crtc_id,
371                        crtc->buffer_id,
372                        crtc->x, crtc->y,
373                        crtc->width, crtc->height);
374                 dump_mode(&crtc->mode);
375
376                 printf("  props:\n");
377                 props = drmModeObjectGetProperties(fd, crtc->crtc_id,
378                                                    DRM_MODE_OBJECT_CRTC);
379                 if (props) {
380                         for (j = 0; j < props->count_props; j++)
381                                 dump_prop(props->props[j],
382                                           props->prop_values[j]);
383                         drmModeFreeObjectProperties(props);
384                 } else {
385                         printf("\tcould not get crtc properties: %s\n",
386                                strerror(errno));
387                 }
388
389                 drmModeFreeCrtc(crtc);
390         }
391         printf("\n");
392 }
393
394 void dump_framebuffers(void)
395 {
396         drmModeFB *fb;
397         int i;
398
399         printf("Frame buffers:\n");
400         printf("id\tsize\tpitch\n");
401         for (i = 0; i < resources->count_fbs; i++) {
402                 fb = drmModeGetFB(fd, resources->fbs[i]);
403
404                 if (!fb) {
405                         fprintf(stderr, "could not get fb %i: %s\n",
406                                 resources->fbs[i], strerror(errno));
407                         continue;
408                 }
409                 printf("%u\t(%ux%u)\t%u\n",
410                        fb->fb_id,
411                        fb->width, fb->height,
412                        fb->pitch);
413
414                 drmModeFreeFB(fb);
415         }
416         printf("\n");
417 }
418
419 static void dump_planes(void)
420 {
421         drmModeObjectPropertiesPtr props;
422         drmModePlaneRes *plane_resources;
423         drmModePlane *ovr;
424         unsigned int i, j;
425
426         plane_resources = drmModeGetPlaneResources(fd);
427         if (!plane_resources) {
428                 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
429                         strerror(errno));
430                 return;
431         }
432
433         printf("Planes:\n");
434         printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n");
435         for (i = 0; i < plane_resources->count_planes; i++) {
436                 ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
437                 if (!ovr) {
438                         fprintf(stderr, "drmModeGetPlane failed: %s\n",
439                                 strerror(errno));
440                         continue;
441                 }
442
443                 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n",
444                        ovr->plane_id, ovr->crtc_id, ovr->fb_id,
445                        ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
446                        ovr->gamma_size);
447
448                 if (!ovr->count_formats)
449                         continue;
450
451                 printf("  formats:");
452                 for (j = 0; j < ovr->count_formats; j++)
453                         printf(" %4.4s", (char *)&ovr->formats[j]);
454                 printf("\n");
455
456                 printf("  props:\n");
457                 props = drmModeObjectGetProperties(fd, ovr->plane_id,
458                                                    DRM_MODE_OBJECT_PLANE);
459                 if (props) {
460                         for (j = 0; j < props->count_props; j++)
461                                 dump_prop(props->props[j],
462                                           props->prop_values[j]);
463                         drmModeFreeObjectProperties(props);
464                 } else {
465                         printf("\tcould not get plane properties: %s\n",
466                                strerror(errno));
467                 }
468
469                 drmModeFreePlane(ovr);
470         }
471         printf("\n");
472
473         drmModeFreePlaneResources(plane_resources);
474         return;
475 }
476
477 /* -----------------------------------------------------------------------------
478  * Connectors and planes
479  */
480
481 /*
482  * Mode setting with the kernel interfaces is a bit of a chore.
483  * First you have to find the connector in question and make sure the
484  * requested mode is available.
485  * Then you need to find the encoder attached to that connector so you
486  * can bind it with a free crtc.
487  */
488 struct connector {
489         uint32_t id;
490         char mode_str[64];
491         char format_str[5];
492         unsigned int fourcc;
493         drmModeModeInfo *mode;
494         drmModeEncoder *encoder;
495         int crtc;
496         int pipe;
497         unsigned int fb_id[2], current_fb_id;
498         struct timeval start;
499
500         int swap_count;
501 };
502
503 struct plane {
504         uint32_t con_id;  /* the id of connector to bind to */
505         uint32_t w, h;
506         unsigned int fb_id;
507         char format_str[5]; /* need to leave room for terminating \0 */
508         unsigned int fourcc;
509 };
510
511 static void
512 connector_find_mode(struct connector *c)
513 {
514         drmModeConnector *connector;
515         int i, j;
516
517         /* First, find the connector & mode */
518         c->mode = NULL;
519         for (i = 0; i < resources->count_connectors; i++) {
520                 connector = drmModeGetConnector(fd, resources->connectors[i]);
521
522                 if (!connector) {
523                         fprintf(stderr, "could not get connector %i: %s\n",
524                                 resources->connectors[i], strerror(errno));
525                         drmModeFreeConnector(connector);
526                         continue;
527                 }
528
529                 if (!connector->count_modes) {
530                         drmModeFreeConnector(connector);
531                         continue;
532                 }
533
534                 if (connector->connector_id != c->id) {
535                         drmModeFreeConnector(connector);
536                         continue;
537                 }
538
539                 for (j = 0; j < connector->count_modes; j++) {
540                         c->mode = &connector->modes[j];
541                         if (!strcmp(c->mode->name, c->mode_str))
542                                 break;
543                 }
544
545                 /* Found it, break out */
546                 if (c->mode)
547                         break;
548
549                 drmModeFreeConnector(connector);
550         }
551
552         if (!c->mode) {
553                 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str);
554                 return;
555         }
556
557         /* Now get the encoder */
558         for (i = 0; i < resources->count_encoders; i++) {
559                 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
560
561                 if (!c->encoder) {
562                         fprintf(stderr, "could not get encoder %i: %s\n",
563                                 resources->encoders[i], strerror(errno));
564                         drmModeFreeEncoder(c->encoder);
565                         continue;
566                 }
567
568                 if (c->encoder->encoder_id  == connector->encoder_id)
569                         break;
570
571                 drmModeFreeEncoder(c->encoder);
572         }
573
574         if (c->crtc == -1)
575                 c->crtc = c->encoder->crtc_id;
576
577         /* and figure out which crtc index it is: */
578         for (i = 0; i < resources->count_crtcs; i++) {
579                 if (c->crtc == resources->crtcs[i]) {
580                         c->pipe = i;
581                         break;
582                 }
583         }
584
585 }
586
587 /* -----------------------------------------------------------------------------
588  * Formats
589  */
590
591 struct color_component {
592         unsigned int length;
593         unsigned int offset;
594 };
595
596 struct rgb_info {
597         struct color_component red;
598         struct color_component green;
599         struct color_component blue;
600         struct color_component alpha;
601 };
602
603 enum yuv_order {
604         YUV_YCbCr = 1,
605         YUV_YCrCb = 2,
606         YUV_YC = 4,
607         YUV_CY = 8,
608 };
609
610 struct yuv_info {
611         enum yuv_order order;
612         unsigned int xsub;
613         unsigned int ysub;
614         unsigned int chroma_stride;
615 };
616
617 struct format_info {
618         unsigned int format;
619         const char *name;
620         const struct rgb_info rgb;
621         const struct yuv_info yuv;
622 };
623
624 #define MAKE_RGB_INFO(rl, ro, bl, bo, gl, go, al, ao) \
625         .rgb = { { (rl), (ro) }, { (bl), (bo) }, { (gl), (go) }, { (al), (ao) } }
626
627 #define MAKE_YUV_INFO(order, xsub, ysub, chroma_stride) \
628         .yuv = { (order), (xsub), (ysub), (chroma_stride) }
629
630 static const struct format_info format_info[] = {
631         /* YUV packed */
632         { DRM_FORMAT_UYVY, "UYVY", MAKE_YUV_INFO(YUV_YCbCr | YUV_CY, 2, 2, 2) },
633         { DRM_FORMAT_VYUY, "VYUY", MAKE_YUV_INFO(YUV_YCrCb | YUV_CY, 2, 2, 2) },
634         { DRM_FORMAT_YUYV, "YUYV", MAKE_YUV_INFO(YUV_YCbCr | YUV_YC, 2, 2, 2) },
635         { DRM_FORMAT_YVYU, "YVYU", MAKE_YUV_INFO(YUV_YCrCb | YUV_YC, 2, 2, 2) },
636         /* YUV semi-planar */
637         { DRM_FORMAT_NV12, "NV12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 2) },
638         { DRM_FORMAT_NV21, "NV21", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 2) },
639         { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) },
640         { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) },
641         /* YUV planar */
642         { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) },
643         /* RGB16 */
644         { DRM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) },
645         { DRM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) },
646         { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) },
647         /* RGB24 */
648         { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
649         { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
650         /* RGB32 */
651         { DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) },
652         { DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) },
653         { DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
654         { DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) },
655 };
656
657 unsigned int format_fourcc(const char *name)
658 {
659         unsigned int i;
660         for (i = 0; i < ARRAY_SIZE(format_info); i++) {
661                 if (!strcmp(format_info[i].name, name))
662                         return format_info[i].format;
663         }
664         return 0;
665 }
666
667 /* -----------------------------------------------------------------------------
668  * Test patterns
669  */
670
671 enum fill_pattern {
672         PATTERN_TILES = 0,
673         PATTERN_PLAIN = 1,
674         PATTERN_SMPTE = 2,
675 };
676
677 struct color_rgb24 {
678         unsigned int value:24;
679 } __attribute__((__packed__));
680
681 struct color_yuv {
682         unsigned char y;
683         unsigned char u;
684         unsigned char v;
685 };
686
687 #define MAKE_YUV_601_Y(r, g, b) \
688         ((( 66 * (r) + 129 * (g) +  25 * (b) + 128) >> 8) + 16)
689 #define MAKE_YUV_601_U(r, g, b) \
690         (((-38 * (r) -  74 * (g) + 112 * (b) + 128) >> 8) + 128)
691 #define MAKE_YUV_601_V(r, g, b) \
692         (((112 * (r) -  94 * (g) -  18 * (b) + 128) >> 8) + 128)
693
694 #define MAKE_YUV_601(r, g, b) \
695         { .y = MAKE_YUV_601_Y(r, g, b), \
696           .u = MAKE_YUV_601_U(r, g, b), \
697           .v = MAKE_YUV_601_V(r, g, b) }
698
699 #define MAKE_RGBA(rgb, r, g, b, a) \
700         ((((r) >> (8 - (rgb)->red.length)) << (rgb)->red.offset) | \
701          (((g) >> (8 - (rgb)->green.length)) << (rgb)->green.offset) | \
702          (((b) >> (8 - (rgb)->blue.length)) << (rgb)->blue.offset) | \
703          (((a) >> (8 - (rgb)->alpha.length)) << (rgb)->alpha.offset))
704
705 #define MAKE_RGB24(rgb, r, g, b) \
706         { .value = MAKE_RGBA(rgb, r, g, b, 0) }
707
708 static void
709 fill_smpte_yuv_planar(const struct yuv_info *yuv,
710                       unsigned char *y_mem, unsigned char *u_mem,
711                       unsigned char *v_mem, unsigned int width,
712                       unsigned int height, unsigned int stride)
713 {
714         const struct color_yuv colors_top[] = {
715                 MAKE_YUV_601(191, 192, 192),    /* grey */
716                 MAKE_YUV_601(192, 192, 0),      /* yellow */
717                 MAKE_YUV_601(0, 192, 192),      /* cyan */
718                 MAKE_YUV_601(0, 192, 0),        /* green */
719                 MAKE_YUV_601(192, 0, 192),      /* magenta */
720                 MAKE_YUV_601(192, 0, 0),        /* red */
721                 MAKE_YUV_601(0, 0, 192),        /* blue */
722         };
723         const struct color_yuv colors_middle[] = {
724                 MAKE_YUV_601(0, 0, 192),        /* blue */
725                 MAKE_YUV_601(19, 19, 19),       /* black */
726                 MAKE_YUV_601(192, 0, 192),      /* magenta */
727                 MAKE_YUV_601(19, 19, 19),       /* black */
728                 MAKE_YUV_601(0, 192, 192),      /* cyan */
729                 MAKE_YUV_601(19, 19, 19),       /* black */
730                 MAKE_YUV_601(192, 192, 192),    /* grey */
731         };
732         const struct color_yuv colors_bottom[] = {
733                 MAKE_YUV_601(0, 33, 76),        /* in-phase */
734                 MAKE_YUV_601(255, 255, 255),    /* super white */
735                 MAKE_YUV_601(50, 0, 106),       /* quadrature */
736                 MAKE_YUV_601(19, 19, 19),       /* black */
737                 MAKE_YUV_601(9, 9, 9),          /* 3.5% */
738                 MAKE_YUV_601(19, 19, 19),       /* 7.5% */
739                 MAKE_YUV_601(29, 29, 29),       /* 11.5% */
740                 MAKE_YUV_601(19, 19, 19),       /* black */
741         };
742         unsigned int cs = yuv->chroma_stride;
743         unsigned int xsub = yuv->xsub;
744         unsigned int ysub = yuv->ysub;
745         unsigned int x;
746         unsigned int y;
747
748         /* Luma */
749         for (y = 0; y < height * 6 / 9; ++y) {
750                 for (x = 0; x < width; ++x)
751                         y_mem[x] = colors_top[x * 7 / width].y;
752                 y_mem += stride;
753         }
754
755         for (; y < height * 7 / 9; ++y) {
756                 for (x = 0; x < width; ++x)
757                         y_mem[x] = colors_middle[x * 7 / width].y;
758                 y_mem += stride;
759         }
760
761         for (; y < height; ++y) {
762                 for (x = 0; x < width * 5 / 7; ++x)
763                         y_mem[x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
764                 for (; x < width * 6 / 7; ++x)
765                         y_mem[x] = colors_bottom[(x - width * 5 / 7) * 3
766                                                  / (width / 7) + 4].y;
767                 for (; x < width; ++x)
768                         y_mem[x] = colors_bottom[7].y;
769                 y_mem += stride;
770         }
771
772         /* Chroma */
773         for (y = 0; y < height / ysub * 6 / 9; ++y) {
774                 for (x = 0; x < width; x += xsub) {
775                         u_mem[x*cs/xsub] = colors_top[x * 7 / width].u;
776                         v_mem[x*cs/xsub] = colors_top[x * 7 / width].v;
777                 }
778                 u_mem += stride * cs / xsub;
779                 v_mem += stride * cs / xsub;
780         }
781
782         for (; y < height / ysub * 7 / 9; ++y) {
783                 for (x = 0; x < width; x += xsub) {
784                         u_mem[x*cs/xsub] = colors_middle[x * 7 / width].u;
785                         v_mem[x*cs/xsub] = colors_middle[x * 7 / width].v;
786                 }
787                 u_mem += stride * cs / xsub;
788                 v_mem += stride * cs / xsub;
789         }
790
791         for (; y < height / ysub; ++y) {
792                 for (x = 0; x < width * 5 / 7; x += xsub) {
793                         u_mem[x*cs/xsub] =
794                                 colors_bottom[x * 4 / (width * 5 / 7)].u;
795                         v_mem[x*cs/xsub] =
796                                 colors_bottom[x * 4 / (width * 5 / 7)].v;
797                 }
798                 for (; x < width * 6 / 7; x += xsub) {
799                         u_mem[x*cs/xsub] = colors_bottom[(x - width * 5 / 7) *
800                                                          3 / (width / 7) + 4].u;
801                         v_mem[x*cs/xsub] = colors_bottom[(x - width * 5 / 7) *
802                                                          3 / (width / 7) + 4].v;
803                 }
804                 for (; x < width; x += xsub) {
805                         u_mem[x*cs/xsub] = colors_bottom[7].u;
806                         v_mem[x*cs/xsub] = colors_bottom[7].v;
807                 }
808                 u_mem += stride * cs / xsub;
809                 v_mem += stride * cs / xsub;
810         }
811 }
812
813 static void
814 fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
815                       unsigned int width, unsigned int height,
816                       unsigned int stride)
817 {
818         const struct color_yuv colors_top[] = {
819                 MAKE_YUV_601(191, 192, 192),    /* grey */
820                 MAKE_YUV_601(192, 192, 0),      /* yellow */
821                 MAKE_YUV_601(0, 192, 192),      /* cyan */
822                 MAKE_YUV_601(0, 192, 0),        /* green */
823                 MAKE_YUV_601(192, 0, 192),      /* magenta */
824                 MAKE_YUV_601(192, 0, 0),        /* red */
825                 MAKE_YUV_601(0, 0, 192),        /* blue */
826         };
827         const struct color_yuv colors_middle[] = {
828                 MAKE_YUV_601(0, 0, 192),        /* blue */
829                 MAKE_YUV_601(19, 19, 19),       /* black */
830                 MAKE_YUV_601(192, 0, 192),      /* magenta */
831                 MAKE_YUV_601(19, 19, 19),       /* black */
832                 MAKE_YUV_601(0, 192, 192),      /* cyan */
833                 MAKE_YUV_601(19, 19, 19),       /* black */
834                 MAKE_YUV_601(192, 192, 192),    /* grey */
835         };
836         const struct color_yuv colors_bottom[] = {
837                 MAKE_YUV_601(0, 33, 76),        /* in-phase */
838                 MAKE_YUV_601(255, 255, 255),    /* super white */
839                 MAKE_YUV_601(50, 0, 106),       /* quadrature */
840                 MAKE_YUV_601(19, 19, 19),       /* black */
841                 MAKE_YUV_601(9, 9, 9),          /* 3.5% */
842                 MAKE_YUV_601(19, 19, 19),       /* 7.5% */
843                 MAKE_YUV_601(29, 29, 29),       /* 11.5% */
844                 MAKE_YUV_601(19, 19, 19),       /* black */
845         };
846         unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
847         unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
848         unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
849         unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0;
850         unsigned int x;
851         unsigned int y;
852
853         /* Luma */
854         for (y = 0; y < height * 6 / 9; ++y) {
855                 for (x = 0; x < width; ++x)
856                         y_mem[2*x] = colors_top[x * 7 / width].y;
857                 y_mem += stride * 2;
858         }
859
860         for (; y < height * 7 / 9; ++y) {
861                 for (x = 0; x < width; ++x)
862                         y_mem[2*x] = colors_middle[x * 7 / width].y;
863                 y_mem += stride * 2;
864         }
865
866         for (; y < height; ++y) {
867                 for (x = 0; x < width * 5 / 7; ++x)
868                         y_mem[2*x] = colors_bottom[x * 4 / (width * 5 / 7)].y;
869                 for (; x < width * 6 / 7; ++x)
870                         y_mem[2*x] = colors_bottom[(x - width * 5 / 7) * 3
871                                                    / (width / 7) + 4].y;
872                 for (; x < width; ++x)
873                         y_mem[2*x] = colors_bottom[7].y;
874                 y_mem += stride * 2;
875         }
876
877         /* Chroma */
878         for (y = 0; y < height * 6 / 9; ++y) {
879                 for (x = 0; x < width; x += 2) {
880                         c_mem[2*x+u] = colors_top[x * 7 / width].u;
881                         c_mem[2*x+v] = colors_top[x * 7 / width].v;
882                 }
883                 c_mem += stride * 2;
884         }
885
886         for (; y < height * 7 / 9; ++y) {
887                 for (x = 0; x < width; x += 2) {
888                         c_mem[2*x+u] = colors_middle[x * 7 / width].u;
889                         c_mem[2*x+v] = colors_middle[x * 7 / width].v;
890                 }
891                 c_mem += stride * 2;
892         }
893
894         for (; y < height; ++y) {
895                 for (x = 0; x < width * 5 / 7; x += 2) {
896                         c_mem[2*x+u] = colors_bottom[x * 4 / (width * 5 / 7)].u;
897                         c_mem[2*x+v] = colors_bottom[x * 4 / (width * 5 / 7)].v;
898                 }
899                 for (; x < width * 6 / 7; x += 2) {
900                         c_mem[2*x+u] = colors_bottom[(x - width * 5 / 7) *
901                                                      3 / (width / 7) + 4].u;
902                         c_mem[2*x+v] = colors_bottom[(x - width * 5 / 7) *
903                                                      3 / (width / 7) + 4].v;
904                 }
905                 for (; x < width; x += 2) {
906                         c_mem[2*x+u] = colors_bottom[7].u;
907                         c_mem[2*x+v] = colors_bottom[7].v;
908                 }
909                 c_mem += stride * 2;
910         }
911 }
912
913 static void
914 fill_smpte_rgb16(const struct rgb_info *rgb, unsigned char *mem,
915                  unsigned int width, unsigned int height, unsigned int stride)
916 {
917         const uint16_t colors_top[] = {
918                 MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
919                 MAKE_RGBA(rgb, 192, 192, 0, 255),       /* yellow */
920                 MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
921                 MAKE_RGBA(rgb, 0, 192, 0, 255),         /* green */
922                 MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
923                 MAKE_RGBA(rgb, 192, 0, 0, 255),         /* red */
924                 MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
925         };
926         const uint16_t colors_middle[] = {
927                 MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
928                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
929                 MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
930                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
931                 MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
932                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
933                 MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
934         };
935         const uint16_t colors_bottom[] = {
936                 MAKE_RGBA(rgb, 0, 33, 76, 255),         /* in-phase */
937                 MAKE_RGBA(rgb, 255, 255, 255, 255),     /* super white */
938                 MAKE_RGBA(rgb, 50, 0, 106, 255),        /* quadrature */
939                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
940                 MAKE_RGBA(rgb, 9, 9, 9, 255),           /* 3.5% */
941                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* 7.5% */
942                 MAKE_RGBA(rgb, 29, 29, 29, 255),        /* 11.5% */
943                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
944         };
945         unsigned int x;
946         unsigned int y;
947
948         for (y = 0; y < height * 6 / 9; ++y) {
949                 for (x = 0; x < width; ++x)
950                         ((uint16_t *)mem)[x] = colors_top[x * 7 / width];
951                 mem += stride;
952         }
953
954         for (; y < height * 7 / 9; ++y) {
955                 for (x = 0; x < width; ++x)
956                         ((uint16_t *)mem)[x] = colors_middle[x * 7 / width];
957                 mem += stride;
958         }
959
960         for (; y < height; ++y) {
961                 for (x = 0; x < width * 5 / 7; ++x)
962                         ((uint16_t *)mem)[x] =
963                                 colors_bottom[x * 4 / (width * 5 / 7)];
964                 for (; x < width * 6 / 7; ++x)
965                         ((uint16_t *)mem)[x] =
966                                 colors_bottom[(x - width * 5 / 7) * 3
967                                               / (width / 7) + 4];
968                 for (; x < width; ++x)
969                         ((uint16_t *)mem)[x] = colors_bottom[7];
970                 mem += stride;
971         }
972 }
973
974 static void
975 fill_smpte_rgb24(const struct rgb_info *rgb, void *mem,
976                  unsigned int width, unsigned int height, unsigned int stride)
977 {
978         const struct color_rgb24 colors_top[] = {
979                 MAKE_RGB24(rgb, 192, 192, 192), /* grey */
980                 MAKE_RGB24(rgb, 192, 192, 0),   /* yellow */
981                 MAKE_RGB24(rgb, 0, 192, 192),   /* cyan */
982                 MAKE_RGB24(rgb, 0, 192, 0),     /* green */
983                 MAKE_RGB24(rgb, 192, 0, 192),   /* magenta */
984                 MAKE_RGB24(rgb, 192, 0, 0),     /* red */
985                 MAKE_RGB24(rgb, 0, 0, 192),     /* blue */
986         };
987         const struct color_rgb24 colors_middle[] = {
988                 MAKE_RGB24(rgb, 0, 0, 192),     /* blue */
989                 MAKE_RGB24(rgb, 19, 19, 19),    /* black */
990                 MAKE_RGB24(rgb, 192, 0, 192),   /* magenta */
991                 MAKE_RGB24(rgb, 19, 19, 19),    /* black */
992                 MAKE_RGB24(rgb, 0, 192, 192),   /* cyan */
993                 MAKE_RGB24(rgb, 19, 19, 19),    /* black */
994                 MAKE_RGB24(rgb, 192, 192, 192), /* grey */
995         };
996         const struct color_rgb24 colors_bottom[] = {
997                 MAKE_RGB24(rgb, 0, 33, 76),     /* in-phase */
998                 MAKE_RGB24(rgb, 255, 255, 255), /* super white */
999                 MAKE_RGB24(rgb, 50, 0, 106),    /* quadrature */
1000                 MAKE_RGB24(rgb, 19, 19, 19),    /* black */
1001                 MAKE_RGB24(rgb, 9, 9, 9),       /* 3.5% */
1002                 MAKE_RGB24(rgb, 19, 19, 19),    /* 7.5% */
1003                 MAKE_RGB24(rgb, 29, 29, 29),    /* 11.5% */
1004                 MAKE_RGB24(rgb, 19, 19, 19),    /* black */
1005         };
1006         unsigned int x;
1007         unsigned int y;
1008
1009         for (y = 0; y < height * 6 / 9; ++y) {
1010                 for (x = 0; x < width; ++x)
1011                         ((struct color_rgb24 *)mem)[x] =
1012                                 colors_top[x * 7 / width];
1013                 mem += stride;
1014         }
1015
1016         for (; y < height * 7 / 9; ++y) {
1017                 for (x = 0; x < width; ++x)
1018                         ((struct color_rgb24 *)mem)[x] =
1019                                 colors_middle[x * 7 / width];
1020                 mem += stride;
1021         }
1022
1023         for (; y < height; ++y) {
1024                 for (x = 0; x < width * 5 / 7; ++x)
1025                         ((struct color_rgb24 *)mem)[x] =
1026                                 colors_bottom[x * 4 / (width * 5 / 7)];
1027                 for (; x < width * 6 / 7; ++x)
1028                         ((struct color_rgb24 *)mem)[x] =
1029                                 colors_bottom[(x - width * 5 / 7) * 3
1030                                               / (width / 7) + 4];
1031                 for (; x < width; ++x)
1032                         ((struct color_rgb24 *)mem)[x] = colors_bottom[7];
1033                 mem += stride;
1034         }
1035 }
1036
1037 static void
1038 fill_smpte_rgb32(const struct rgb_info *rgb, unsigned char *mem,
1039                  unsigned int width, unsigned int height, unsigned int stride)
1040 {
1041         const uint32_t colors_top[] = {
1042                 MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
1043                 MAKE_RGBA(rgb, 192, 192, 0, 255),       /* yellow */
1044                 MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
1045                 MAKE_RGBA(rgb, 0, 192, 0, 255),         /* green */
1046                 MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
1047                 MAKE_RGBA(rgb, 192, 0, 0, 255),         /* red */
1048                 MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
1049         };
1050         const uint32_t colors_middle[] = {
1051                 MAKE_RGBA(rgb, 0, 0, 192, 255),         /* blue */
1052                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
1053                 MAKE_RGBA(rgb, 192, 0, 192, 255),       /* magenta */
1054                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
1055                 MAKE_RGBA(rgb, 0, 192, 192, 255),       /* cyan */
1056                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
1057                 MAKE_RGBA(rgb, 192, 192, 192, 255),     /* grey */
1058         };
1059         const uint32_t colors_bottom[] = {
1060                 MAKE_RGBA(rgb, 0, 33, 76, 255),         /* in-phase */
1061                 MAKE_RGBA(rgb, 255, 255, 255, 255),     /* super white */
1062                 MAKE_RGBA(rgb, 50, 0, 106, 255),        /* quadrature */
1063                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
1064                 MAKE_RGBA(rgb, 9, 9, 9, 255),           /* 3.5% */
1065                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* 7.5% */
1066                 MAKE_RGBA(rgb, 29, 29, 29, 255),        /* 11.5% */
1067                 MAKE_RGBA(rgb, 19, 19, 19, 255),        /* black */
1068         };
1069         unsigned int x;
1070         unsigned int y;
1071
1072         for (y = 0; y < height * 6 / 9; ++y) {
1073                 for (x = 0; x < width; ++x)
1074                         ((uint32_t *)mem)[x] = colors_top[x * 7 / width];
1075                 mem += stride;
1076         }
1077
1078         for (; y < height * 7 / 9; ++y) {
1079                 for (x = 0; x < width; ++x)
1080                         ((uint32_t *)mem)[x] = colors_middle[x * 7 / width];
1081                 mem += stride;
1082         }
1083
1084         for (; y < height; ++y) {
1085                 for (x = 0; x < width * 5 / 7; ++x)
1086                         ((uint32_t *)mem)[x] =
1087                                 colors_bottom[x * 4 / (width * 5 / 7)];
1088                 for (; x < width * 6 / 7; ++x)
1089                         ((uint32_t *)mem)[x] =
1090                                 colors_bottom[(x - width * 5 / 7) * 3
1091                                               / (width / 7) + 4];
1092                 for (; x < width; ++x)
1093                         ((uint32_t *)mem)[x] = colors_bottom[7];
1094                 mem += stride;
1095         }
1096 }
1097
1098 static void
1099 fill_smpte(const struct format_info *info, void *planes[3], unsigned int width,
1100            unsigned int height, unsigned int stride)
1101 {
1102         unsigned char *u, *v;
1103
1104         switch (info->format) {
1105         case DRM_FORMAT_UYVY:
1106         case DRM_FORMAT_VYUY:
1107         case DRM_FORMAT_YUYV:
1108         case DRM_FORMAT_YVYU:
1109                 return fill_smpte_yuv_packed(&info->yuv, planes[0], width,
1110                                              height, stride);
1111
1112         case DRM_FORMAT_NV12:
1113         case DRM_FORMAT_NV21:
1114         case DRM_FORMAT_NV16:
1115         case DRM_FORMAT_NV61:
1116                 u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
1117                 v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
1118                 return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
1119                                              width, height, stride);
1120
1121         case DRM_FORMAT_YVU420:
1122                 return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
1123                                              planes[2], width, height, stride);
1124
1125         case DRM_FORMAT_RGB565:
1126         case DRM_FORMAT_ARGB1555:
1127         case DRM_FORMAT_XRGB1555:
1128                 return fill_smpte_rgb16(&info->rgb, planes[0],
1129                                         width, height, stride);
1130         case DRM_FORMAT_BGR888:
1131         case DRM_FORMAT_RGB888:
1132                 return fill_smpte_rgb24(&info->rgb, planes[0],
1133                                         width, height, stride);
1134         case DRM_FORMAT_ARGB8888:
1135         case DRM_FORMAT_BGRA8888:
1136         case DRM_FORMAT_XRGB8888:
1137         case DRM_FORMAT_BGRX8888:
1138                 return fill_smpte_rgb32(&info->rgb, planes[0],
1139                                         width, height, stride);
1140         }
1141 }
1142
1143 /* swap these for big endian.. */
1144 #define RED   2
1145 #define GREEN 1
1146 #define BLUE  0
1147
1148 static void
1149 make_pwetty(void *data, int width, int height, int stride)
1150 {
1151 #ifdef HAVE_CAIRO
1152         cairo_surface_t *surface;
1153         cairo_t *cr;
1154         int x, y;
1155
1156         surface = cairo_image_surface_create_for_data(data,
1157                                                       CAIRO_FORMAT_ARGB32,
1158                                                       width, height,
1159                                                       stride);
1160         cr = cairo_create(surface);
1161         cairo_surface_destroy(surface);
1162
1163         cairo_set_line_cap(cr, CAIRO_LINE_CAP_SQUARE);
1164         for (x = 0; x < width; x += 250)
1165                 for (y = 0; y < height; y += 250) {
1166                         char buf[64];
1167
1168                         cairo_move_to(cr, x, y - 20);
1169                         cairo_line_to(cr, x, y + 20);
1170                         cairo_move_to(cr, x - 20, y);
1171                         cairo_line_to(cr, x + 20, y);
1172                         cairo_new_sub_path(cr);
1173                         cairo_arc(cr, x, y, 10, 0, M_PI * 2);
1174                         cairo_set_line_width(cr, 4);
1175                         cairo_set_source_rgb(cr, 0, 0, 0);
1176                         cairo_stroke_preserve(cr);
1177                         cairo_set_source_rgb(cr, 1, 1, 1);
1178                         cairo_set_line_width(cr, 2);
1179                         cairo_stroke(cr);
1180
1181                         snprintf(buf, sizeof buf, "%d, %d", x, y);
1182                         cairo_move_to(cr, x + 20, y + 20);
1183                         cairo_text_path(cr, buf);
1184                         cairo_set_source_rgb(cr, 0, 0, 0);
1185                         cairo_stroke_preserve(cr);
1186                         cairo_set_source_rgb(cr, 1, 1, 1);
1187                         cairo_fill(cr);
1188                 }
1189
1190         cairo_destroy(cr);
1191 #endif
1192 }
1193
1194 static void
1195 fill_tiles_yuv_planar(const struct yuv_info *yuv,
1196                       unsigned char *y_mem, unsigned char *u_mem,
1197                       unsigned char *v_mem, unsigned int width,
1198                       unsigned int height, unsigned int stride)
1199 {
1200         unsigned int cs = yuv->chroma_stride;
1201         unsigned int xsub = yuv->xsub;
1202         unsigned int ysub = yuv->ysub;
1203         unsigned int x;
1204         unsigned int y;
1205
1206         for (y = 0; y < height; ++y) {
1207                 for (x = 0; x < width; ++x) {
1208                         div_t d = div(x+y, width);
1209                         uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
1210                                        + 0x000a1120 * (d.rem >> 6);
1211                         struct color_yuv color =
1212                                 MAKE_YUV_601((rgb32 >> 16) & 0xff,
1213                                              (rgb32 >> 8) & 0xff, rgb32 & 0xff);
1214
1215                         y_mem[x] = color.y;
1216                         u_mem[x/xsub*cs] = color.u;
1217                         v_mem[x/xsub*cs] = color.v;
1218                 }
1219
1220                 y_mem += stride;
1221                 if ((y + 1) % ysub == 0) {
1222                         u_mem += stride * cs / xsub;
1223                         v_mem += stride * cs / xsub;
1224                 }
1225         }
1226 }
1227
1228 static void
1229 fill_tiles_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
1230                       unsigned int width, unsigned int height,
1231                       unsigned int stride)
1232 {
1233         unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
1234         unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
1235         unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
1236         unsigned int v = (yuv->order & YUV_YCbCr) ? 2 : 0;
1237         unsigned int x;
1238         unsigned int y;
1239
1240         for (y = 0; y < height; ++y) {
1241                 for (x = 0; x < width; x += 2) {
1242                         div_t d = div(x+y, width);
1243                         uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
1244                                        + 0x000a1120 * (d.rem >> 6);
1245                         struct color_yuv color =
1246                                 MAKE_YUV_601((rgb32 >> 16) & 0xff,
1247                                              (rgb32 >> 8) & 0xff, rgb32 & 0xff);
1248
1249                         y_mem[2*x] = color.y;
1250                         c_mem[2*x+u] = color.u;
1251                         y_mem[2*x+2] = color.y;
1252                         c_mem[2*x+v] = color.v;
1253                 }
1254
1255                 y_mem += stride;
1256                 c_mem += stride;
1257         }
1258 }
1259
1260 static void
1261 fill_tiles_rgb16(const struct rgb_info *rgb, unsigned char *mem,
1262                  unsigned int width, unsigned int height, unsigned int stride)
1263 {
1264         unsigned int x, y;
1265
1266         for (y = 0; y < height; ++y) {
1267                 for (x = 0; x < width; ++x) {
1268                         div_t d = div(x+y, width);
1269                         uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
1270                                        + 0x000a1120 * (d.rem >> 6);
1271                         uint16_t color =
1272                                 MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff,
1273                                           (rgb32 >> 8) & 0xff, rgb32 & 0xff,
1274                                           255);
1275
1276                         ((uint16_t *)mem)[x] = color;
1277                 }
1278                 mem += stride;
1279         }
1280 }
1281
1282 static void
1283 fill_tiles_rgb24(const struct rgb_info *rgb, unsigned char *mem,
1284                  unsigned int width, unsigned int height, unsigned int stride)
1285 {
1286         unsigned int x, y;
1287
1288         for (y = 0; y < height; ++y) {
1289                 for (x = 0; x < width; ++x) {
1290                         div_t d = div(x+y, width);
1291                         uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
1292                                        + 0x000a1120 * (d.rem >> 6);
1293                         struct color_rgb24 color =
1294                                 MAKE_RGB24(rgb, (rgb32 >> 16) & 0xff,
1295                                            (rgb32 >> 8) & 0xff, rgb32 & 0xff);
1296
1297                         ((struct color_rgb24 *)mem)[x] = color;
1298                 }
1299                 mem += stride;
1300         }
1301 }
1302
1303 static void
1304 fill_tiles_rgb32(const struct rgb_info *rgb, unsigned char *mem,
1305                  unsigned int width, unsigned int height, unsigned int stride)
1306 {
1307         unsigned char *mem_base = mem;
1308         unsigned int x, y;
1309
1310         for (y = 0; y < height; ++y) {
1311                 for (x = 0; x < width; ++x) {
1312                         div_t d = div(x+y, width);
1313                         uint32_t rgb32 = 0x00130502 * (d.quot >> 6)
1314                                        + 0x000a1120 * (d.rem >> 6);
1315                         uint32_t color =
1316                                 MAKE_RGBA(rgb, (rgb32 >> 16) & 0xff,
1317                                           (rgb32 >> 8) & 0xff, rgb32 & 0xff,
1318                                           255);
1319
1320                         ((uint32_t *)mem)[x] = color;
1321                 }
1322                 mem += stride;
1323         }
1324
1325         make_pwetty(mem_base, width, height, stride);
1326 }
1327
1328 static void
1329 fill_tiles(const struct format_info *info, void *planes[3], unsigned int width,
1330            unsigned int height, unsigned int stride)
1331 {
1332         unsigned char *u, *v;
1333
1334         switch (info->format) {
1335         case DRM_FORMAT_UYVY:
1336         case DRM_FORMAT_VYUY:
1337         case DRM_FORMAT_YUYV:
1338         case DRM_FORMAT_YVYU:
1339                 return fill_tiles_yuv_packed(&info->yuv, planes[0],
1340                                              width, height, stride);
1341
1342         case DRM_FORMAT_NV12:
1343         case DRM_FORMAT_NV21:
1344         case DRM_FORMAT_NV16:
1345         case DRM_FORMAT_NV61:
1346                 u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
1347                 v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
1348                 return fill_tiles_yuv_planar(&info->yuv, planes[0], u, v,
1349                                              width, height, stride);
1350
1351         case DRM_FORMAT_YVU420:
1352                 return fill_tiles_yuv_planar(&info->yuv, planes[0], planes[1],
1353                                              planes[2], width, height, stride);
1354
1355         case DRM_FORMAT_RGB565:
1356         case DRM_FORMAT_ARGB1555:
1357         case DRM_FORMAT_XRGB1555:
1358                 return fill_tiles_rgb16(&info->rgb, planes[0],
1359                                         width, height, stride);
1360         case DRM_FORMAT_BGR888:
1361         case DRM_FORMAT_RGB888:
1362                 return fill_tiles_rgb24(&info->rgb, planes[0],
1363                                         width, height, stride);
1364         case DRM_FORMAT_ARGB8888:
1365         case DRM_FORMAT_BGRA8888:
1366         case DRM_FORMAT_XRGB8888:
1367         case DRM_FORMAT_BGRX8888:
1368                 return fill_tiles_rgb32(&info->rgb, planes[0],
1369                                         width, height, stride);
1370         }
1371 }
1372
1373 static void
1374 fill_plain(const struct format_info *info, void *planes[3], unsigned int width,
1375            unsigned int height, unsigned int stride)
1376 {
1377         memset(planes[0], 0x77, stride * height);
1378 }
1379
1380 /*
1381  * fill_pattern - Fill a buffer with a test pattern
1382  * @format: Pixel format
1383  * @pattern: Test pattern
1384  * @buffer: Buffer memory
1385  * @width: Width in pixels
1386  * @height: Height in pixels
1387  * @stride: Line stride (pitch) in bytes
1388  *
1389  * Fill the buffer with the test pattern specified by the pattern parameter.
1390  * Supported formats vary depending on the selected pattern.
1391  */
1392 static void
1393 fill_pattern(unsigned int format, enum fill_pattern pattern,
1394              void *planes[3],
1395              unsigned int width, unsigned int height, unsigned int stride)
1396 {
1397         const struct format_info *info = NULL;
1398         unsigned int i;
1399
1400         for (i = 0; i < ARRAY_SIZE(format_info); ++i) {
1401                 if (format_info[i].format == format) {
1402                         info = &format_info[i];
1403                         break;
1404                 }
1405         }
1406
1407         if (info == NULL)
1408                 return;
1409
1410         switch (pattern) {
1411         case PATTERN_TILES:
1412                 return fill_tiles(info, planes, width, height, stride);
1413
1414         case PATTERN_SMPTE:
1415                 return fill_smpte(info, planes, width, height, stride);
1416
1417         case PATTERN_PLAIN:
1418                 return fill_plain(info, planes, width, height, stride);
1419
1420         default:
1421                 printf("Error: unsupported test pattern %u.\n", pattern);
1422                 break;
1423         }
1424 }
1425
1426 /* -----------------------------------------------------------------------------
1427  * Buffers management
1428  */
1429
1430 static struct kms_bo *
1431 allocate_buffer(struct kms_driver *kms,
1432                 int width, int height, int *stride)
1433 {
1434         struct kms_bo *bo;
1435         unsigned bo_attribs[] = {
1436                 KMS_WIDTH,   0,
1437                 KMS_HEIGHT,  0,
1438                 KMS_BO_TYPE, KMS_BO_TYPE_SCANOUT_X8R8G8B8,
1439                 KMS_TERMINATE_PROP_LIST
1440         };
1441         int ret;
1442
1443         bo_attribs[1] = width;
1444         bo_attribs[3] = height;
1445
1446         ret = kms_bo_create(kms, bo_attribs, &bo);
1447         if (ret) {
1448                 fprintf(stderr, "failed to alloc buffer: %s\n",
1449                         strerror(-ret));
1450                 return NULL;
1451         }
1452
1453         ret = kms_bo_get_prop(bo, KMS_PITCH, stride);
1454         if (ret) {
1455                 fprintf(stderr, "failed to retreive buffer stride: %s\n",
1456                         strerror(-ret));
1457                 kms_bo_destroy(&bo);
1458                 return NULL;
1459         }
1460
1461         return bo;
1462 }
1463
1464 static struct kms_bo *
1465 create_test_buffer(struct kms_driver *kms, unsigned int format,
1466                    int width, int height, int handles[4],
1467                    int pitches[4], int offsets[4], enum fill_pattern pattern)
1468 {
1469         struct kms_bo *bo;
1470         int ret, stride;
1471         void *planes[3];
1472         void *virtual;
1473
1474         bo = allocate_buffer(kms, width, height, &pitches[0]);
1475         if (!bo)
1476                 return NULL;
1477
1478         ret = kms_bo_map(bo, &virtual);
1479         if (ret) {
1480                 fprintf(stderr, "failed to map buffer: %s\n",
1481                         strerror(-ret));
1482                 kms_bo_destroy(&bo);
1483                 return NULL;
1484         }
1485
1486         /* just testing a limited # of formats to test single
1487          * and multi-planar path.. would be nice to add more..
1488          */
1489         switch (format) {
1490         case DRM_FORMAT_UYVY:
1491         case DRM_FORMAT_VYUY:
1492         case DRM_FORMAT_YUYV:
1493         case DRM_FORMAT_YVYU:
1494                 pitches[0] = width * 2;
1495                 offsets[0] = 0;
1496                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1497
1498                 planes[0] = virtual;
1499                 break;
1500
1501         case DRM_FORMAT_NV12:
1502         case DRM_FORMAT_NV21:
1503         case DRM_FORMAT_NV16:
1504         case DRM_FORMAT_NV61:
1505                 pitches[0] = width;
1506                 offsets[0] = 0;
1507                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1508                 pitches[1] = width;
1509                 offsets[1] = width * height;
1510                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]);
1511
1512                 planes[0] = virtual;
1513                 planes[1] = virtual + offsets[1];
1514                 break;
1515
1516         case DRM_FORMAT_YVU420:
1517                 pitches[0] = width;
1518                 offsets[0] = 0;
1519                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1520                 pitches[1] = width / 2;
1521                 offsets[1] = width * height;
1522                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]);
1523                 pitches[2] = width / 2;
1524                 offsets[2] = offsets[1] + (width * height) / 4;
1525                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[2]);
1526
1527                 planes[0] = virtual;
1528                 planes[1] = virtual + offsets[1];
1529                 planes[2] = virtual + offsets[2];
1530                 break;
1531
1532         case DRM_FORMAT_RGB565:
1533         case DRM_FORMAT_ARGB1555:
1534         case DRM_FORMAT_XRGB1555:
1535                 pitches[0] = width * 2;
1536                 offsets[0] = 0;
1537                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1538
1539                 planes[0] = virtual;
1540                 break;
1541
1542         case DRM_FORMAT_BGR888:
1543         case DRM_FORMAT_RGB888:
1544                 pitches[0] = width * 3;
1545                 offsets[0] = 0;
1546                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1547
1548                 planes[0] = virtual;
1549                 break;
1550
1551         case DRM_FORMAT_ARGB8888:
1552         case DRM_FORMAT_BGRA8888:
1553         case DRM_FORMAT_XRGB8888:
1554         case DRM_FORMAT_BGRX8888:
1555                 pitches[0] = width * 4;
1556                 offsets[0] = 0;
1557                 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1558
1559                 planes[0] = virtual;
1560                 break;
1561         }
1562
1563         fill_pattern(format, pattern, planes, width, height, pitches[0]);
1564         kms_bo_unmap(bo);
1565
1566         return bo;
1567 }
1568
1569 /* -------------------------------------------------------------------------- */
1570
1571 void
1572 page_flip_handler(int fd, unsigned int frame,
1573                   unsigned int sec, unsigned int usec, void *data)
1574 {
1575         struct connector *c;
1576         unsigned int new_fb_id;
1577         struct timeval end;
1578         double t;
1579
1580         c = data;
1581         if (c->current_fb_id == c->fb_id[0])
1582                 new_fb_id = c->fb_id[1];
1583         else
1584                 new_fb_id = c->fb_id[0];
1585
1586         drmModePageFlip(fd, c->crtc, new_fb_id,
1587                         DRM_MODE_PAGE_FLIP_EVENT, c);
1588         c->current_fb_id = new_fb_id;
1589         c->swap_count++;
1590         if (c->swap_count == 60) {
1591                 gettimeofday(&end, NULL);
1592                 t = end.tv_sec + end.tv_usec * 1e-6 -
1593                         (c->start.tv_sec + c->start.tv_usec * 1e-6);
1594                 fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t);
1595                 c->swap_count = 0;
1596                 c->start = end;
1597         }
1598 }
1599
1600 static int
1601 set_plane(struct kms_driver *kms, struct connector *c, struct plane *p)
1602 {
1603         drmModePlaneRes *plane_resources;
1604         drmModePlane *ovr;
1605         uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
1606         uint32_t plane_id = 0;
1607         struct kms_bo *plane_bo;
1608         uint32_t plane_flags = 0;
1609         int ret, crtc_x, crtc_y, crtc_w, crtc_h;
1610         unsigned int i;
1611
1612         /* find an unused plane which can be connected to our crtc */
1613         plane_resources = drmModeGetPlaneResources(fd);
1614         if (!plane_resources) {
1615                 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
1616                         strerror(errno));
1617                 return -1;
1618         }
1619
1620         for (i = 0; i < plane_resources->count_planes && !plane_id; i++) {
1621                 ovr = drmModeGetPlane(fd, plane_resources->planes[i]);
1622                 if (!ovr) {
1623                         fprintf(stderr, "drmModeGetPlane failed: %s\n",
1624                                 strerror(errno));
1625                         return -1;
1626                 }
1627
1628                 if ((ovr->possible_crtcs & (1 << c->pipe)) && !ovr->crtc_id)
1629                         plane_id = ovr->plane_id;
1630
1631                 drmModeFreePlane(ovr);
1632         }
1633
1634         fprintf(stderr, "testing %dx%d@%s overlay plane\n",
1635                         p->w, p->h, p->format_str);
1636
1637         if (!plane_id) {
1638                 fprintf(stderr, "failed to find plane!\n");
1639                 return -1;
1640         }
1641
1642         plane_bo = create_test_buffer(kms, p->fourcc, p->w, p->h, handles,
1643                                       pitches, offsets, PATTERN_TILES);
1644         if (plane_bo == NULL)
1645                 return -1;
1646
1647         /* just use single plane format for now.. */
1648         if (drmModeAddFB2(fd, p->w, p->h, p->fourcc,
1649                         handles, pitches, offsets, &p->fb_id, plane_flags)) {
1650                 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
1651                 return -1;
1652         }
1653
1654         /* ok, boring.. but for now put in middle of screen: */
1655         crtc_x = c->mode->hdisplay / 3;
1656         crtc_y = c->mode->vdisplay / 3;
1657         crtc_w = crtc_x;
1658         crtc_h = crtc_y;
1659
1660         /* note src coords (last 4 args) are in Q16 format */
1661         if (drmModeSetPlane(fd, plane_id, c->crtc, p->fb_id,
1662                             plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
1663                             0, 0, p->w << 16, p->h << 16)) {
1664                 fprintf(stderr, "failed to enable plane: %s\n",
1665                         strerror(errno));
1666                 return -1;
1667         }
1668
1669         return 0;
1670 }
1671
1672 static void
1673 set_mode(struct connector *c, int count, struct plane *p, int plane_count,
1674                 int page_flip)
1675 {
1676         struct kms_driver *kms;
1677         struct kms_bo *bo, *other_bo;
1678         unsigned int fb_id, other_fb_id;
1679         int i, j, ret, width, height, x;
1680         uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
1681         drmEventContext evctx;
1682
1683         width = 0;
1684         height = 0;
1685         for (i = 0; i < count; i++) {
1686                 connector_find_mode(&c[i]);
1687                 if (c[i].mode == NULL)
1688                         continue;
1689                 width += c[i].mode->hdisplay;
1690                 if (height < c[i].mode->vdisplay)
1691                         height = c[i].mode->vdisplay;
1692         }
1693
1694         ret = kms_create(fd, &kms);
1695         if (ret) {
1696                 fprintf(stderr, "failed to create kms driver: %s\n",
1697                         strerror(-ret));
1698                 return;
1699         }
1700
1701         bo = create_test_buffer(kms, c->fourcc, width, height, handles,
1702                                 pitches, offsets, PATTERN_SMPTE);
1703         if (bo == NULL)
1704                 return;
1705
1706         ret = drmModeAddFB2(fd, width, height, c->fourcc,
1707                             handles, pitches, offsets, &fb_id, 0);
1708         if (ret) {
1709                 fprintf(stderr, "failed to add fb (%ux%u): %s\n",
1710                         width, height, strerror(errno));
1711                 return;
1712         }
1713
1714         x = 0;
1715         for (i = 0; i < count; i++) {
1716                 if (c[i].mode == NULL)
1717                         continue;
1718
1719                 printf("setting mode %s@%s on connector %d, crtc %d\n",
1720                        c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc);
1721
1722                 ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0,
1723                                      &c[i].id, 1, c[i].mode);
1724
1725                 /* XXX: Actually check if this is needed */
1726                 drmModeDirtyFB(fd, fb_id, NULL, 0);
1727
1728                 x += c[i].mode->hdisplay;
1729
1730                 if (ret) {
1731                         fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
1732                         return;
1733                 }
1734
1735                 /* if we have a plane/overlay to show, set that up now: */
1736                 for (j = 0; j < plane_count; j++)
1737                         if (p[j].con_id == c[i].id)
1738                                 if (set_plane(kms, &c[i], &p[j]))
1739                                         return;
1740         }
1741
1742         if (!page_flip)
1743                 return;
1744         
1745         other_bo = create_test_buffer(kms, c->fourcc, width, height, handles,
1746                                       pitches, offsets, PATTERN_PLAIN);
1747         if (other_bo == NULL)
1748                 return;
1749
1750         ret = drmModeAddFB2(fd, width, height, c->fourcc, handles, pitches, offsets,
1751                             &other_fb_id, 0);
1752         if (ret) {
1753                 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
1754                 return;
1755         }
1756
1757         for (i = 0; i < count; i++) {
1758                 if (c[i].mode == NULL)
1759                         continue;
1760
1761                 ret = drmModePageFlip(fd, c[i].crtc, other_fb_id,
1762                                       DRM_MODE_PAGE_FLIP_EVENT, &c[i]);
1763                 if (ret) {
1764                         fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
1765                         return;
1766                 }
1767                 gettimeofday(&c[i].start, NULL);
1768                 c[i].swap_count = 0;
1769                 c[i].fb_id[0] = fb_id;
1770                 c[i].fb_id[1] = other_fb_id;
1771                 c[i].current_fb_id = other_fb_id;
1772         }
1773
1774         memset(&evctx, 0, sizeof evctx);
1775         evctx.version = DRM_EVENT_CONTEXT_VERSION;
1776         evctx.vblank_handler = NULL;
1777         evctx.page_flip_handler = page_flip_handler;
1778         
1779         while (1) {
1780 #if 0
1781                 struct pollfd pfd[2];
1782
1783                 pfd[0].fd = 0;
1784                 pfd[0].events = POLLIN;
1785                 pfd[1].fd = fd;
1786                 pfd[1].events = POLLIN;
1787
1788                 if (poll(pfd, 2, -1) < 0) {
1789                         fprintf(stderr, "poll error\n");
1790                         break;
1791                 }
1792
1793                 if (pfd[0].revents)
1794                         break;
1795 #else
1796                 struct timeval timeout = { .tv_sec = 3, .tv_usec = 0 };
1797                 fd_set fds;
1798                 int ret;
1799
1800                 FD_ZERO(&fds);
1801                 FD_SET(0, &fds);
1802                 FD_SET(fd, &fds);
1803                 ret = select(fd + 1, &fds, NULL, NULL, &timeout);
1804
1805                 if (ret <= 0) {
1806                         fprintf(stderr, "select timed out or error (ret %d)\n",
1807                                 ret);
1808                         continue;
1809                 } else if (FD_ISSET(0, &fds)) {
1810                         break;
1811                 }
1812 #endif
1813
1814                 drmHandleEvent(fd, &evctx);
1815         }
1816
1817         kms_bo_destroy(&bo);
1818         kms_bo_destroy(&other_bo);
1819         kms_destroy(&kms);
1820 }
1821
1822 extern char *optarg;
1823 extern int optind, opterr, optopt;
1824 static char optstr[] = "ecpmfs:P:v";
1825
1826 #define min(a, b)       ((a) < (b) ? (a) : (b))
1827
1828 static int parse_connector(struct connector *c, const char *arg)
1829 {
1830         unsigned int len;
1831         const char *p;
1832         char *endp;
1833
1834         c->crtc = -1;
1835         strcpy(c->format_str, "XR24");
1836
1837         c->id = strtoul(arg, &endp, 10);
1838         if (*endp == '@') {
1839                 arg = endp + 1;
1840                 c->crtc = strtoul(arg, &endp, 10);
1841         }
1842         if (*endp != ':')
1843                 return -1;
1844
1845         arg = endp + 1;
1846
1847         p = strchrnul(arg, '@');
1848         len = min(sizeof c->mode_str - 1, p - arg);
1849         strncpy(c->mode_str, arg, len);
1850         c->mode_str[len] = '\0';
1851
1852         if (*p == '@') {
1853                 strncpy(c->format_str, p + 1, 4);
1854                 c->format_str[4] = '\0';
1855
1856                 c->fourcc = format_fourcc(p + 1);
1857                 if (c->fourcc == 0)  {
1858                         fprintf(stderr, "unknown format %s\n", c->format_str);
1859                         return -1;
1860                 }
1861         }
1862
1863         return 0;
1864 }
1865
1866 static int parse_plane(struct plane *p, const char *arg)
1867 {
1868         strcpy(p->format_str, "XR24");
1869
1870         if (sscanf(arg, "%d:%dx%d@%4s", &p->con_id, &p->w, &p->h, &p->format_str) != 4 &&
1871             sscanf(arg, "%d:%dx%d", &p->con_id, &p->w, &p->h) != 3)
1872                 return -1;
1873
1874         p->fourcc = format_fourcc(p->format_str);
1875         if (p->fourcc == 0) {
1876                 fprintf(stderr, "unknown format %s\n", p->format_str);
1877                 return -1;
1878         }
1879
1880         return 0;
1881 }
1882
1883 void usage(char *name)
1884 {
1885         fprintf(stderr, "usage: %s [-ecpmf]\n", name);
1886         fprintf(stderr, "\t-e\tlist encoders\n");
1887         fprintf(stderr, "\t-c\tlist connectors\n");
1888         fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
1889         fprintf(stderr, "\t-m\tlist modes\n");
1890         fprintf(stderr, "\t-f\tlist framebuffers\n");
1891         fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
1892         fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n");
1893         fprintf(stderr, "\t-P <connector_id>:<w>x<h>[@<format>]\tset a plane\n");
1894         fprintf(stderr, "\n\tDefault is to dump all info.\n");
1895         exit(0);
1896 }
1897
1898 #define dump_resource(res) if (res) dump_##res()
1899
1900 static int page_flipping_supported(void)
1901 {
1902         /*FIXME: generic ioctl needed? */
1903         return 1;
1904 #if 0
1905         int ret, value;
1906         struct drm_i915_getparam gp;
1907
1908         gp.param = I915_PARAM_HAS_PAGEFLIPPING;
1909         gp.value = &value;
1910
1911         ret = drmCommandWriteRead(fd, DRM_I915_GETPARAM, &gp, sizeof(gp));
1912         if (ret) {
1913                 fprintf(stderr, "drm_i915_getparam: %m\n");
1914                 return 0;
1915         }
1916
1917         return *gp.value;
1918 #endif
1919 }
1920
1921 int main(int argc, char **argv)
1922 {
1923         int c;
1924         int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
1925         int test_vsync = 0;
1926         char *modules[] = { "i915", "radeon", "nouveau", "vmwgfx", "omapdrm", "exynos" };
1927         unsigned int i;
1928         int count = 0, plane_count = 0;
1929         struct connector con_args[2];
1930         struct plane plane_args[2] = {0};
1931         
1932         opterr = 0;
1933         while ((c = getopt(argc, argv, optstr)) != -1) {
1934                 switch (c) {
1935                 case 'e':
1936                         encoders = 1;
1937                         break;
1938                 case 'c':
1939                         connectors = 1;
1940                         break;
1941                 case 'p':
1942                         crtcs = 1;
1943                         planes = 1;
1944                         break;
1945                 case 'm':
1946                         modes = 1;
1947                         break;
1948                 case 'f':
1949                         framebuffers = 1;
1950                         break;
1951                 case 'v':
1952                         test_vsync = 1;
1953                         break;
1954                 case 's':
1955                         if (parse_connector(&con_args[count], optarg) < 0)
1956                                 usage(argv[0]);
1957                         count++;                                      
1958                         break;
1959                 case 'P':
1960                         if (parse_plane(&plane_args[plane_count], optarg) < 0)
1961                                 usage(argv[0]);
1962                         plane_count++;
1963                         break;
1964                 default:
1965                         usage(argv[0]);
1966                         break;
1967                 }
1968         }
1969
1970         if (argc == 1)
1971                 encoders = connectors = crtcs = planes = modes = framebuffers = 1;
1972
1973         for (i = 0; i < ARRAY_SIZE(modules); i++) {
1974                 printf("trying to load module %s...", modules[i]);
1975                 fd = drmOpen(modules[i], NULL);
1976                 if (fd < 0) {
1977                         printf("failed.\n");
1978                 } else {
1979                         printf("success.\n");
1980                         break;
1981                 }
1982         }
1983
1984         if (test_vsync && !page_flipping_supported()) {
1985                 fprintf(stderr, "page flipping not supported by drm.\n");
1986                 return -1;
1987         }
1988
1989         if (i == ARRAY_SIZE(modules)) {
1990                 fprintf(stderr, "failed to load any modules, aborting.\n");
1991                 return -1;
1992         }
1993
1994         resources = drmModeGetResources(fd);
1995         if (!resources) {
1996                 fprintf(stderr, "drmModeGetResources failed: %s\n",
1997                         strerror(errno));
1998                 drmClose(fd);
1999                 return 1;
2000         }
2001
2002         dump_resource(encoders);
2003         dump_resource(connectors);
2004         dump_resource(crtcs);
2005         dump_resource(planes);
2006         dump_resource(framebuffers);
2007
2008         if (count > 0) {
2009                 set_mode(con_args, count, plane_args, plane_count, test_vsync);
2010                 getchar();
2011         }
2012
2013         drmModeFreeResources(resources);
2014
2015         return 0;
2016 }