aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorsrinivas pulukuru2014-11-14 23:35:52 -0600
committersrinivas pulukuru2015-01-30 16:04:01 -0600
commit19087e509db2ff1487220d2a2a7142a86ef1586a (patch)
tree4758acfd4db74d8d39651e59ef975e80c3da7db7
parentaeaa7d3d78fc0784bc55fc8e1e5dd07bdb6f1fa4 (diff)
downloadlibdrm-19087e509db2ff1487220d2a2a7142a86ef1586a.tar.gz
libdrm-19087e509db2ff1487220d2a2a7142a86ef1586a.tar.xz
libdrm-19087e509db2ff1487220d2a2a7142a86ef1586a.zip
modetest: add support for modetest
added support for scaling, window coordinates, refresh rate for mode setting Added other options such as Query options: -c list connectors -e list encoders -f list framebuffers -p list CRTCs and planes (pipes) Test options: -P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>] set a plane -s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>] set a mode -v test vsynced page flipping -w <obj_id>:<prop_name>:<value> set property Generic options: -d drop master after mode set -M module use the given driver -D device use the given device Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Ilia Mirkin <imirkin@alum.mit.edu> Signed-off-by: Vincent Abriou <vincent.abriou@st.com> Signed-off-by: Rob Clark <robclark@freedesktop.org> Signed-off-by: srinivas pulukuru <srinivas.pulukuru@ti.com> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
-rw-r--r--tests/modetest/Makefile.am4
-rw-r--r--tests/modetest/buffers.c265
-rw-r--r--tests/modetest/buffers.h5
-rw-r--r--tests/modetest/modetest.c1242
4 files changed, 1100 insertions, 416 deletions
diff --git a/tests/modetest/Makefile.am b/tests/modetest/Makefile.am
index 065ae132..93767678 100644
--- a/tests/modetest/Makefile.am
+++ b/tests/modetest/Makefile.am
@@ -1,4 +1,6 @@
1AM_CFLAGS = \ 1AM_CFLAGS = $(filter-out -Wpointer-arith, $(WARN_CFLAGS))
2
3AM_CFLAGS += \
2 -I$(top_srcdir)/include/drm \ 4 -I$(top_srcdir)/include/drm \
3 -I$(top_srcdir)/libkms/ \ 5 -I$(top_srcdir)/libkms/ \
4 -I$(top_srcdir) 6 -I$(top_srcdir)
diff --git a/tests/modetest/buffers.c b/tests/modetest/buffers.c
index 50863811..8206ce31 100644
--- a/tests/modetest/buffers.c
+++ b/tests/modetest/buffers.c
@@ -100,19 +100,47 @@ static const struct format_info format_info[] = {
100 { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) }, 100 { DRM_FORMAT_NV16, "NV16", MAKE_YUV_INFO(YUV_YCbCr, 2, 1, 2) },
101 { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) }, 101 { DRM_FORMAT_NV61, "NV61", MAKE_YUV_INFO(YUV_YCrCb, 2, 1, 2) },
102 /* YUV planar */ 102 /* YUV planar */
103 { DRM_FORMAT_YUV420, "YU12", MAKE_YUV_INFO(YUV_YCbCr, 2, 2, 1) },
103 { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) }, 104 { DRM_FORMAT_YVU420, "YV12", MAKE_YUV_INFO(YUV_YCrCb, 2, 2, 1) },
104 /* RGB16 */ 105 /* RGB16 */
106 { DRM_FORMAT_ARGB4444, "AR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 4, 12) },
107 { DRM_FORMAT_XRGB4444, "XR12", MAKE_RGB_INFO(4, 8, 4, 4, 4, 0, 0, 0) },
108 { DRM_FORMAT_ABGR4444, "AB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 4, 12) },
109 { DRM_FORMAT_XBGR4444, "XB12", MAKE_RGB_INFO(4, 0, 4, 4, 4, 8, 0, 0) },
110 { DRM_FORMAT_RGBA4444, "RA12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 4, 0) },
111 { DRM_FORMAT_RGBX4444, "RX12", MAKE_RGB_INFO(4, 12, 4, 8, 4, 4, 0, 0) },
112 { DRM_FORMAT_BGRA4444, "BA12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 4, 0) },
113 { DRM_FORMAT_BGRX4444, "BX12", MAKE_RGB_INFO(4, 4, 4, 8, 4, 12, 0, 0) },
105 { DRM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) }, 114 { DRM_FORMAT_ARGB1555, "AR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 1, 15) },
106 { DRM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) }, 115 { DRM_FORMAT_XRGB1555, "XR15", MAKE_RGB_INFO(5, 10, 5, 5, 5, 0, 0, 0) },
116 { DRM_FORMAT_ABGR1555, "AB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 1, 15) },
117 { DRM_FORMAT_XBGR1555, "XB15", MAKE_RGB_INFO(5, 0, 5, 5, 5, 10, 0, 0) },
118 { DRM_FORMAT_RGBA5551, "RA15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 1, 0) },
119 { DRM_FORMAT_RGBX5551, "RX15", MAKE_RGB_INFO(5, 11, 5, 6, 5, 1, 0, 0) },
120 { DRM_FORMAT_BGRA5551, "BA15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 1, 0) },
121 { DRM_FORMAT_BGRX5551, "BX15", MAKE_RGB_INFO(5, 1, 5, 6, 5, 11, 0, 0) },
107 { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) }, 122 { DRM_FORMAT_RGB565, "RG16", MAKE_RGB_INFO(5, 11, 6, 5, 5, 0, 0, 0) },
123 { DRM_FORMAT_BGR565, "BG16", MAKE_RGB_INFO(5, 0, 6, 5, 5, 11, 0, 0) },
108 /* RGB24 */ 124 /* RGB24 */
109 { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) }, 125 { DRM_FORMAT_BGR888, "BG24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
110 { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, 126 { DRM_FORMAT_RGB888, "RG24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
111 /* RGB32 */ 127 /* RGB32 */
112 { DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) }, 128 { DRM_FORMAT_ARGB8888, "AR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 8, 24) },
113 { DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) },
114 { DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) }, 129 { DRM_FORMAT_XRGB8888, "XR24", MAKE_RGB_INFO(8, 16, 8, 8, 8, 0, 0, 0) },
130 { DRM_FORMAT_ABGR8888, "AB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 8, 24) },
131 { DRM_FORMAT_XBGR8888, "XB24", MAKE_RGB_INFO(8, 0, 8, 8, 8, 16, 0, 0) },
132 { DRM_FORMAT_RGBA8888, "RA24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 8, 0) },
133 { DRM_FORMAT_RGBX8888, "RX24", MAKE_RGB_INFO(8, 24, 8, 16, 8, 8, 0, 0) },
134 { DRM_FORMAT_BGRA8888, "BA24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 8, 0) },
115 { DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) }, 135 { DRM_FORMAT_BGRX8888, "BX24", MAKE_RGB_INFO(8, 8, 8, 16, 8, 24, 0, 0) },
136 { DRM_FORMAT_ARGB2101010, "AR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 2, 30) },
137 { DRM_FORMAT_XRGB2101010, "XR30", MAKE_RGB_INFO(10, 20, 10, 10, 10, 0, 0, 0) },
138 { DRM_FORMAT_ABGR2101010, "AB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 2, 30) },
139 { DRM_FORMAT_XBGR2101010, "XB30", MAKE_RGB_INFO(10, 0, 10, 10, 10, 20, 0, 0) },
140 { DRM_FORMAT_RGBA1010102, "RA30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 2, 0) },
141 { DRM_FORMAT_RGBX1010102, "RX30", MAKE_RGB_INFO(10, 22, 10, 12, 10, 2, 0, 0) },
142 { DRM_FORMAT_BGRA1010102, "BA30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 2, 0) },
143 { DRM_FORMAT_BGRX1010102, "BX30", MAKE_RGB_INFO(10, 2, 10, 12, 10, 22, 0, 0) },
116}; 144};
117 145
118unsigned int format_fourcc(const char *name) 146unsigned int format_fourcc(const char *name)
@@ -309,13 +337,13 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
309 for (y = 0; y < height * 6 / 9; ++y) { 337 for (y = 0; y < height * 6 / 9; ++y) {
310 for (x = 0; x < width; ++x) 338 for (x = 0; x < width; ++x)
311 y_mem[2*x] = colors_top[x * 7 / width].y; 339 y_mem[2*x] = colors_top[x * 7 / width].y;
312 y_mem += stride * 2; 340 y_mem += stride;
313 } 341 }
314 342
315 for (; y < height * 7 / 9; ++y) { 343 for (; y < height * 7 / 9; ++y) {
316 for (x = 0; x < width; ++x) 344 for (x = 0; x < width; ++x)
317 y_mem[2*x] = colors_middle[x * 7 / width].y; 345 y_mem[2*x] = colors_middle[x * 7 / width].y;
318 y_mem += stride * 2; 346 y_mem += stride;
319 } 347 }
320 348
321 for (; y < height; ++y) { 349 for (; y < height; ++y) {
@@ -326,7 +354,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
326 / (width / 7) + 4].y; 354 / (width / 7) + 4].y;
327 for (; x < width; ++x) 355 for (; x < width; ++x)
328 y_mem[2*x] = colors_bottom[7].y; 356 y_mem[2*x] = colors_bottom[7].y;
329 y_mem += stride * 2; 357 y_mem += stride;
330 } 358 }
331 359
332 /* Chroma */ 360 /* Chroma */
@@ -335,7 +363,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
335 c_mem[2*x+u] = colors_top[x * 7 / width].u; 363 c_mem[2*x+u] = colors_top[x * 7 / width].u;
336 c_mem[2*x+v] = colors_top[x * 7 / width].v; 364 c_mem[2*x+v] = colors_top[x * 7 / width].v;
337 } 365 }
338 c_mem += stride * 2; 366 c_mem += stride;
339 } 367 }
340 368
341 for (; y < height * 7 / 9; ++y) { 369 for (; y < height * 7 / 9; ++y) {
@@ -343,7 +371,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
343 c_mem[2*x+u] = colors_middle[x * 7 / width].u; 371 c_mem[2*x+u] = colors_middle[x * 7 / width].u;
344 c_mem[2*x+v] = colors_middle[x * 7 / width].v; 372 c_mem[2*x+v] = colors_middle[x * 7 / width].v;
345 } 373 }
346 c_mem += stride * 2; 374 c_mem += stride;
347 } 375 }
348 376
349 for (; y < height; ++y) { 377 for (; y < height; ++y) {
@@ -361,7 +389,7 @@ fill_smpte_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
361 c_mem[2*x+u] = colors_bottom[7].u; 389 c_mem[2*x+u] = colors_bottom[7].u;
362 c_mem[2*x+v] = colors_bottom[7].v; 390 c_mem[2*x+v] = colors_bottom[7].v;
363 } 391 }
364 c_mem += stride * 2; 392 c_mem += stride;
365 } 393 }
366} 394}
367 395
@@ -573,23 +601,55 @@ fill_smpte(const struct format_info *info, void *planes[3], unsigned int width,
573 return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v, 601 return fill_smpte_yuv_planar(&info->yuv, planes[0], u, v,
574 width, height, stride); 602 width, height, stride);
575 603
576 case DRM_FORMAT_YVU420: 604 case DRM_FORMAT_YUV420:
577 return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1], 605 return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[1],
578 planes[2], width, height, stride); 606 planes[2], width, height, stride);
579 607
608 case DRM_FORMAT_YVU420:
609 return fill_smpte_yuv_planar(&info->yuv, planes[0], planes[2],
610 planes[1], width, height, stride);
611
612 case DRM_FORMAT_ARGB4444:
613 case DRM_FORMAT_XRGB4444:
614 case DRM_FORMAT_ABGR4444:
615 case DRM_FORMAT_XBGR4444:
616 case DRM_FORMAT_RGBA4444:
617 case DRM_FORMAT_RGBX4444:
618 case DRM_FORMAT_BGRA4444:
619 case DRM_FORMAT_BGRX4444:
580 case DRM_FORMAT_RGB565: 620 case DRM_FORMAT_RGB565:
621 case DRM_FORMAT_BGR565:
581 case DRM_FORMAT_ARGB1555: 622 case DRM_FORMAT_ARGB1555:
582 case DRM_FORMAT_XRGB1555: 623 case DRM_FORMAT_XRGB1555:
624 case DRM_FORMAT_ABGR1555:
625 case DRM_FORMAT_XBGR1555:
626 case DRM_FORMAT_RGBA5551:
627 case DRM_FORMAT_RGBX5551:
628 case DRM_FORMAT_BGRA5551:
629 case DRM_FORMAT_BGRX5551:
583 return fill_smpte_rgb16(&info->rgb, planes[0], 630 return fill_smpte_rgb16(&info->rgb, planes[0],
584 width, height, stride); 631 width, height, stride);
632
585 case DRM_FORMAT_BGR888: 633 case DRM_FORMAT_BGR888:
586 case DRM_FORMAT_RGB888: 634 case DRM_FORMAT_RGB888:
587 return fill_smpte_rgb24(&info->rgb, planes[0], 635 return fill_smpte_rgb24(&info->rgb, planes[0],
588 width, height, stride); 636 width, height, stride);
589 case DRM_FORMAT_ARGB8888: 637 case DRM_FORMAT_ARGB8888:
590 case DRM_FORMAT_BGRA8888:
591 case DRM_FORMAT_XRGB8888: 638 case DRM_FORMAT_XRGB8888:
639 case DRM_FORMAT_ABGR8888:
640 case DRM_FORMAT_XBGR8888:
641 case DRM_FORMAT_RGBA8888:
642 case DRM_FORMAT_RGBX8888:
643 case DRM_FORMAT_BGRA8888:
592 case DRM_FORMAT_BGRX8888: 644 case DRM_FORMAT_BGRX8888:
645 case DRM_FORMAT_ARGB2101010:
646 case DRM_FORMAT_XRGB2101010:
647 case DRM_FORMAT_ABGR2101010:
648 case DRM_FORMAT_XBGR2101010:
649 case DRM_FORMAT_RGBA1010102:
650 case DRM_FORMAT_RGBX1010102:
651 case DRM_FORMAT_BGRA1010102:
652 case DRM_FORMAT_BGRX1010102:
593 return fill_smpte_rgb32(&info->rgb, planes[0], 653 return fill_smpte_rgb32(&info->rgb, planes[0],
594 width, height, stride); 654 width, height, stride);
595 } 655 }
@@ -601,15 +661,32 @@ fill_smpte(const struct format_info *info, void *planes[3], unsigned int width,
601#define BLUE 0 661#define BLUE 0
602 662
603static void 663static void
604make_pwetty(void *data, int width, int height, int stride) 664make_pwetty(void *data, int width, int height, int stride, uint32_t format)
605{ 665{
606#ifdef HAVE_CAIRO 666#ifdef HAVE_CAIRO
607 cairo_surface_t *surface; 667 cairo_surface_t *surface;
608 cairo_t *cr; 668 cairo_t *cr;
609 int x, y; 669 int x, y;
670 cairo_format_t cairo_format;
671
672 /* we can ignore the order of R,G,B channels */
673 switch (format) {
674 case DRM_FORMAT_XRGB8888:
675 case DRM_FORMAT_ARGB8888:
676 case DRM_FORMAT_XBGR8888:
677 case DRM_FORMAT_ABGR8888:
678 cairo_format = CAIRO_FORMAT_ARGB32;
679 break;
680 case DRM_FORMAT_RGB565:
681 case DRM_FORMAT_BGR565:
682 cairo_format = CAIRO_FORMAT_RGB16_565;
683 break;
684 default:
685 return;
686 }
610 687
611 surface = cairo_image_surface_create_for_data(data, 688 surface = cairo_image_surface_create_for_data(data,
612 CAIRO_FORMAT_ARGB32, 689 cairo_format,
613 width, height, 690 width, height,
614 stride); 691 stride);
615 cr = cairo_create(surface); 692 cr = cairo_create(surface);
@@ -647,11 +724,12 @@ make_pwetty(void *data, int width, int height, int stride)
647} 724}
648 725
649static void 726static void
650fill_tiles_yuv_planar(const struct yuv_info *yuv, 727fill_tiles_yuv_planar(const struct format_info *info,
651 unsigned char *y_mem, unsigned char *u_mem, 728 unsigned char *y_mem, unsigned char *u_mem,
652 unsigned char *v_mem, unsigned int width, 729 unsigned char *v_mem, unsigned int width,
653 unsigned int height, unsigned int stride) 730 unsigned int height, unsigned int stride)
654{ 731{
732 const struct yuv_info *yuv = &info->yuv;
655 unsigned int cs = yuv->chroma_stride; 733 unsigned int cs = yuv->chroma_stride;
656 unsigned int xsub = yuv->xsub; 734 unsigned int xsub = yuv->xsub;
657 unsigned int ysub = yuv->ysub; 735 unsigned int ysub = yuv->ysub;
@@ -681,10 +759,11 @@ fill_tiles_yuv_planar(const struct yuv_info *yuv,
681} 759}
682 760
683static void 761static void
684fill_tiles_yuv_packed(const struct yuv_info *yuv, unsigned char *mem, 762fill_tiles_yuv_packed(const struct format_info *info, unsigned char *mem,
685 unsigned int width, unsigned int height, 763 unsigned int width, unsigned int height,
686 unsigned int stride) 764 unsigned int stride)
687{ 765{
766 const struct yuv_info *yuv = &info->yuv;
688 unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1; 767 unsigned char *y_mem = (yuv->order & YUV_YC) ? mem : mem + 1;
689 unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1; 768 unsigned char *c_mem = (yuv->order & YUV_CY) ? mem : mem + 1;
690 unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0; 769 unsigned int u = (yuv->order & YUV_YCrCb) ? 2 : 0;
@@ -713,9 +792,11 @@ fill_tiles_yuv_packed(const struct yuv_info *yuv, unsigned char *mem,
713} 792}
714 793
715static void 794static void
716fill_tiles_rgb16(const struct rgb_info *rgb, unsigned char *mem, 795fill_tiles_rgb16(const struct format_info *info, unsigned char *mem,
717 unsigned int width, unsigned int height, unsigned int stride) 796 unsigned int width, unsigned int height, unsigned int stride)
718{ 797{
798 const struct rgb_info *rgb = &info->rgb;
799 unsigned char *mem_base = mem;
719 unsigned int x, y; 800 unsigned int x, y;
720 801
721 for (y = 0; y < height; ++y) { 802 for (y = 0; y < height; ++y) {
@@ -732,12 +813,15 @@ fill_tiles_rgb16(const struct rgb_info *rgb, unsigned char *mem,
732 } 813 }
733 mem += stride; 814 mem += stride;
734 } 815 }
816
817 make_pwetty(mem_base, width, height, stride, info->format);
735} 818}
736 819
737static void 820static void
738fill_tiles_rgb24(const struct rgb_info *rgb, unsigned char *mem, 821fill_tiles_rgb24(const struct format_info *info, unsigned char *mem,
739 unsigned int width, unsigned int height, unsigned int stride) 822 unsigned int width, unsigned int height, unsigned int stride)
740{ 823{
824 const struct rgb_info *rgb = &info->rgb;
741 unsigned int x, y; 825 unsigned int x, y;
742 826
743 for (y = 0; y < height; ++y) { 827 for (y = 0; y < height; ++y) {
@@ -756,9 +840,10 @@ fill_tiles_rgb24(const struct rgb_info *rgb, unsigned char *mem,
756} 840}
757 841
758static void 842static void
759fill_tiles_rgb32(const struct rgb_info *rgb, unsigned char *mem, 843fill_tiles_rgb32(const struct format_info *info, unsigned char *mem,
760 unsigned int width, unsigned int height, unsigned int stride) 844 unsigned int width, unsigned int height, unsigned int stride)
761{ 845{
846 const struct rgb_info *rgb = &info->rgb;
762 unsigned char *mem_base = mem; 847 unsigned char *mem_base = mem;
763 unsigned int x, y; 848 unsigned int x, y;
764 849
@@ -777,7 +862,7 @@ fill_tiles_rgb32(const struct rgb_info *rgb, unsigned char *mem,
777 mem += stride; 862 mem += stride;
778 } 863 }
779 864
780 make_pwetty(mem_base, width, height, stride); 865 make_pwetty(mem_base, width, height, stride, info->format);
781} 866}
782 867
783static void 868static void
@@ -791,7 +876,7 @@ fill_tiles(const struct format_info *info, void *planes[3], unsigned int width,
791 case DRM_FORMAT_VYUY: 876 case DRM_FORMAT_VYUY:
792 case DRM_FORMAT_YUYV: 877 case DRM_FORMAT_YUYV:
793 case DRM_FORMAT_YVYU: 878 case DRM_FORMAT_YVYU:
794 return fill_tiles_yuv_packed(&info->yuv, planes[0], 879 return fill_tiles_yuv_packed(info, planes[0],
795 width, height, stride); 880 width, height, stride);
796 881
797 case DRM_FORMAT_NV12: 882 case DRM_FORMAT_NV12:
@@ -800,27 +885,59 @@ fill_tiles(const struct format_info *info, void *planes[3], unsigned int width,
800 case DRM_FORMAT_NV61: 885 case DRM_FORMAT_NV61:
801 u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1; 886 u = info->yuv.order & YUV_YCbCr ? planes[1] : planes[1] + 1;
802 v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1; 887 v = info->yuv.order & YUV_YCrCb ? planes[1] : planes[1] + 1;
803 return fill_tiles_yuv_planar(&info->yuv, planes[0], u, v, 888 return fill_tiles_yuv_planar(info, planes[0], u, v,
804 width, height, stride); 889 width, height, stride);
805 890
806 case DRM_FORMAT_YVU420: 891 case DRM_FORMAT_YUV420:
807 return fill_tiles_yuv_planar(&info->yuv, planes[0], planes[1], 892 return fill_tiles_yuv_planar(info, planes[0], planes[1],
808 planes[2], width, height, stride); 893 planes[2], width, height, stride);
809 894
895 case DRM_FORMAT_YVU420:
896 return fill_tiles_yuv_planar(info, planes[0], planes[2],
897 planes[1], width, height, stride);
898
899 case DRM_FORMAT_ARGB4444:
900 case DRM_FORMAT_XRGB4444:
901 case DRM_FORMAT_ABGR4444:
902 case DRM_FORMAT_XBGR4444:
903 case DRM_FORMAT_RGBA4444:
904 case DRM_FORMAT_RGBX4444:
905 case DRM_FORMAT_BGRA4444:
906 case DRM_FORMAT_BGRX4444:
810 case DRM_FORMAT_RGB565: 907 case DRM_FORMAT_RGB565:
908 case DRM_FORMAT_BGR565:
811 case DRM_FORMAT_ARGB1555: 909 case DRM_FORMAT_ARGB1555:
812 case DRM_FORMAT_XRGB1555: 910 case DRM_FORMAT_XRGB1555:
813 return fill_tiles_rgb16(&info->rgb, planes[0], 911 case DRM_FORMAT_ABGR1555:
912 case DRM_FORMAT_XBGR1555:
913 case DRM_FORMAT_RGBA5551:
914 case DRM_FORMAT_RGBX5551:
915 case DRM_FORMAT_BGRA5551:
916 case DRM_FORMAT_BGRX5551:
917 return fill_tiles_rgb16(info, planes[0],
814 width, height, stride); 918 width, height, stride);
919
815 case DRM_FORMAT_BGR888: 920 case DRM_FORMAT_BGR888:
816 case DRM_FORMAT_RGB888: 921 case DRM_FORMAT_RGB888:
817 return fill_tiles_rgb24(&info->rgb, planes[0], 922 return fill_tiles_rgb24(info, planes[0],
818 width, height, stride); 923 width, height, stride);
819 case DRM_FORMAT_ARGB8888: 924 case DRM_FORMAT_ARGB8888:
820 case DRM_FORMAT_BGRA8888:
821 case DRM_FORMAT_XRGB8888: 925 case DRM_FORMAT_XRGB8888:
926 case DRM_FORMAT_ABGR8888:
927 case DRM_FORMAT_XBGR8888:
928 case DRM_FORMAT_RGBA8888:
929 case DRM_FORMAT_RGBX8888:
930 case DRM_FORMAT_BGRA8888:
822 case DRM_FORMAT_BGRX8888: 931 case DRM_FORMAT_BGRX8888:
823 return fill_tiles_rgb32(&info->rgb, planes[0], 932 case DRM_FORMAT_ARGB2101010:
933 case DRM_FORMAT_XRGB2101010:
934 case DRM_FORMAT_ABGR2101010:
935 case DRM_FORMAT_XBGR2101010:
936 case DRM_FORMAT_RGBA1010102:
937 case DRM_FORMAT_RGBX1010102:
938 case DRM_FORMAT_BGRA1010102:
939 case DRM_FORMAT_BGRX1010102:
940 return fill_tiles_rgb32(info, planes[0],
824 width, height, stride); 941 width, height, stride);
825 } 942 }
826} 943}
@@ -882,8 +999,8 @@ fill_pattern(unsigned int format, enum fill_pattern pattern, void *planes[3],
882 */ 999 */
883 1000
884static struct kms_bo * 1001static struct kms_bo *
885allocate_buffer(struct kms_driver *kms, 1002allocate_buffer(struct kms_driver *kms, unsigned int width, unsigned int height,
886 int width, int height, int *stride) 1003 unsigned int *stride)
887{ 1004{
888 struct kms_bo *bo; 1005 struct kms_bo *bo;
889 unsigned bo_attribs[] = { 1006 unsigned bo_attribs[] = {
@@ -917,15 +1034,33 @@ allocate_buffer(struct kms_driver *kms,
917 1034
918struct kms_bo * 1035struct kms_bo *
919create_test_buffer(struct kms_driver *kms, unsigned int format, 1036create_test_buffer(struct kms_driver *kms, unsigned int format,
920 int width, int height, int handles[4], 1037 unsigned int width, unsigned int height,
921 int pitches[4], int offsets[4], enum fill_pattern pattern) 1038 unsigned int handles[4], unsigned int pitches[4],
1039 unsigned int offsets[4], enum fill_pattern pattern)
922{ 1040{
1041 unsigned int virtual_height;
923 struct kms_bo *bo; 1042 struct kms_bo *bo;
924 int ret, stride; 1043 void *planes[3] = { 0, };
925 void *planes[3];
926 void *virtual; 1044 void *virtual;
1045 int ret;
1046
1047 switch (format) {
1048 case DRM_FORMAT_NV12:
1049 case DRM_FORMAT_NV21:
1050 virtual_height = height * 3 / 2;
1051 break;
927 1052
928 bo = allocate_buffer(kms, width, height, &pitches[0]); 1053 case DRM_FORMAT_NV16:
1054 case DRM_FORMAT_NV61:
1055 virtual_height = height * 2;
1056 break;
1057
1058 default:
1059 virtual_height = height;
1060 break;
1061 }
1062
1063 bo = allocate_buffer(kms, width, virtual_height, &pitches[0]);
929 if (!bo) 1064 if (!bo)
930 return NULL; 1065 return NULL;
931 1066
@@ -945,9 +1080,9 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
945 case DRM_FORMAT_VYUY: 1080 case DRM_FORMAT_VYUY:
946 case DRM_FORMAT_YUYV: 1081 case DRM_FORMAT_YUYV:
947 case DRM_FORMAT_YVYU: 1082 case DRM_FORMAT_YVYU:
948 pitches[0] = width * 2;
949 offsets[0] = 0; 1083 offsets[0] = 0;
950 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); 1084 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1085 kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
951 1086
952 planes[0] = virtual; 1087 planes[0] = virtual;
953 break; 1088 break;
@@ -956,26 +1091,27 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
956 case DRM_FORMAT_NV21: 1091 case DRM_FORMAT_NV21:
957 case DRM_FORMAT_NV16: 1092 case DRM_FORMAT_NV16:
958 case DRM_FORMAT_NV61: 1093 case DRM_FORMAT_NV61:
959 pitches[0] = width;
960 offsets[0] = 0; 1094 offsets[0] = 0;
961 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); 1095 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
962 pitches[1] = width; 1096 kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
963 offsets[1] = width * height; 1097 pitches[1] = pitches[0];
1098 offsets[1] = pitches[0] * height;
964 kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]); 1099 kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]);
965 1100
966 planes[0] = virtual; 1101 planes[0] = virtual;
967 planes[1] = virtual + offsets[1]; 1102 planes[1] = virtual + offsets[1];
968 break; 1103 break;
969 1104
1105 case DRM_FORMAT_YUV420:
970 case DRM_FORMAT_YVU420: 1106 case DRM_FORMAT_YVU420:
971 pitches[0] = width;
972 offsets[0] = 0; 1107 offsets[0] = 0;
973 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); 1108 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
974 pitches[1] = width / 2; 1109 kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
975 offsets[1] = width * height; 1110 pitches[1] = pitches[0] / 2;
1111 offsets[1] = pitches[0] * height;
976 kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]); 1112 kms_bo_get_prop(bo, KMS_HANDLE, &handles[1]);
977 pitches[2] = width / 2; 1113 pitches[2] = pitches[1];
978 offsets[2] = offsets[1] + (width * height) / 4; 1114 offsets[2] = offsets[1] + pitches[1] * height / 2;
979 kms_bo_get_prop(bo, KMS_HANDLE, &handles[2]); 1115 kms_bo_get_prop(bo, KMS_HANDLE, &handles[2]);
980 1116
981 planes[0] = virtual; 1117 planes[0] = virtual;
@@ -983,32 +1119,45 @@ create_test_buffer(struct kms_driver *kms, unsigned int format,
983 planes[2] = virtual + offsets[2]; 1119 planes[2] = virtual + offsets[2];
984 break; 1120 break;
985 1121
986 case DRM_FORMAT_RGB565: 1122 case DRM_FORMAT_ARGB4444:
1123 case DRM_FORMAT_XRGB4444:
1124 case DRM_FORMAT_ABGR4444:
1125 case DRM_FORMAT_XBGR4444:
1126 case DRM_FORMAT_RGBA4444:
1127 case DRM_FORMAT_RGBX4444:
1128 case DRM_FORMAT_BGRA4444:
1129 case DRM_FORMAT_BGRX4444:
987 case DRM_FORMAT_ARGB1555: 1130 case DRM_FORMAT_ARGB1555:
988 case DRM_FORMAT_XRGB1555: 1131 case DRM_FORMAT_XRGB1555:
989 pitches[0] = width * 2; 1132 case DRM_FORMAT_ABGR1555:
990 offsets[0] = 0; 1133 case DRM_FORMAT_XBGR1555:
991 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); 1134 case DRM_FORMAT_RGBA5551:
992 1135 case DRM_FORMAT_RGBX5551:
993 planes[0] = virtual; 1136 case DRM_FORMAT_BGRA5551:
994 break; 1137 case DRM_FORMAT_BGRX5551:
995 1138 case DRM_FORMAT_RGB565:
1139 case DRM_FORMAT_BGR565:
996 case DRM_FORMAT_BGR888: 1140 case DRM_FORMAT_BGR888:
997 case DRM_FORMAT_RGB888: 1141 case DRM_FORMAT_RGB888:
998 pitches[0] = width * 3;
999 offsets[0] = 0;
1000 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1001
1002 planes[0] = virtual;
1003 break;
1004
1005 case DRM_FORMAT_ARGB8888: 1142 case DRM_FORMAT_ARGB8888:
1006 case DRM_FORMAT_BGRA8888:
1007 case DRM_FORMAT_XRGB8888: 1143 case DRM_FORMAT_XRGB8888:
1144 case DRM_FORMAT_ABGR8888:
1145 case DRM_FORMAT_XBGR8888:
1146 case DRM_FORMAT_RGBA8888:
1147 case DRM_FORMAT_RGBX8888:
1148 case DRM_FORMAT_BGRA8888:
1008 case DRM_FORMAT_BGRX8888: 1149 case DRM_FORMAT_BGRX8888:
1009 pitches[0] = width * 4; 1150 case DRM_FORMAT_ARGB2101010:
1151 case DRM_FORMAT_XRGB2101010:
1152 case DRM_FORMAT_ABGR2101010:
1153 case DRM_FORMAT_XBGR2101010:
1154 case DRM_FORMAT_RGBA1010102:
1155 case DRM_FORMAT_RGBX1010102:
1156 case DRM_FORMAT_BGRA1010102:
1157 case DRM_FORMAT_BGRX1010102:
1010 offsets[0] = 0; 1158 offsets[0] = 0;
1011 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]); 1159 kms_bo_get_prop(bo, KMS_HANDLE, &handles[0]);
1160 kms_bo_get_prop(bo, KMS_PITCH, &pitches[0]);
1012 1161
1013 planes[0] = virtual; 1162 planes[0] = virtual;
1014 break; 1163 break;
diff --git a/tests/modetest/buffers.h b/tests/modetest/buffers.h
index 2b15ce50..e320389b 100644
--- a/tests/modetest/buffers.h
+++ b/tests/modetest/buffers.h
@@ -37,8 +37,9 @@ enum fill_pattern {
37}; 37};
38 38
39struct kms_bo *create_test_buffer(struct kms_driver *kms, unsigned int format, 39struct kms_bo *create_test_buffer(struct kms_driver *kms, unsigned int format,
40 int width, int height, int handles[4], int pitches[4], 40 unsigned int width, unsigned int height,
41 int offsets[4], enum fill_pattern pattern); 41 unsigned int handles[4], unsigned int pitches[4],
42 unsigned int offsets[4], enum fill_pattern pattern);
42 43
43unsigned int format_fourcc(const char *name); 44unsigned int format_fourcc(const char *name);
44 45
diff --git a/tests/modetest/modetest.c b/tests/modetest/modetest.c
index ff45dc9a..0591d7bd 100644
--- a/tests/modetest/modetest.c
+++ b/tests/modetest/modetest.c
@@ -40,6 +40,8 @@
40#include "config.h" 40#include "config.h"
41 41
42#include <assert.h> 42#include <assert.h>
43#include <ctype.h>
44#include <stdbool.h>
43#include <stdio.h> 45#include <stdio.h>
44#include <stdlib.h> 46#include <stdlib.h>
45#include <stdint.h> 47#include <stdint.h>
@@ -57,18 +59,68 @@
57 59
58#include "buffers.h" 60#include "buffers.h"
59 61
60drmModeRes *resources; 62struct crtc {
61int fd, modes; 63 drmModeCrtc *crtc;
64 drmModeObjectProperties *props;
65 drmModePropertyRes **props_info;
66 drmModeModeInfo *mode;
67};
68
69struct encoder {
70 drmModeEncoder *encoder;
71};
72
73struct connector {
74 drmModeConnector *connector;
75 drmModeObjectProperties *props;
76 drmModePropertyRes **props_info;
77};
78
79struct fb {
80 drmModeFB *fb;
81};
82
83struct plane {
84 drmModePlane *plane;
85 drmModeObjectProperties *props;
86 drmModePropertyRes **props_info;
87};
88
89struct resources {
90 drmModeRes *res;
91 drmModePlaneRes *plane_res;
92
93 struct crtc *crtcs;
94 struct encoder *encoders;
95 struct connector *connectors;
96 struct fb *fbs;
97 struct plane *planes;
98};
99
100struct device {
101 int fd;
102
103 struct resources *resources;
104 struct kms_driver *kms;
105
106 struct {
107 unsigned int width;
108 unsigned int height;
109
110 unsigned int fb_id;
111 struct kms_bo *bo;
112 } mode;
113};
62 114
63#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0])) 115#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
64 116
65struct type_name { 117struct type_name {
66 int type; 118 int type;
67 char *name; 119 const char *name;
68}; 120};
69 121
70#define type_name_fn(res) \ 122#define type_name_fn(res) \
71char * res##_str(int type) { \ 123const char * res##_str(int type) { \
72 unsigned int i; \ 124 unsigned int i; \
73 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 125 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
74 if (res##_names[i].type == type) \ 126 if (res##_names[i].type == type) \
@@ -85,7 +137,7 @@ struct type_name encoder_type_names[] = {
85 { DRM_MODE_ENCODER_TVDAC, "TVDAC" }, 137 { DRM_MODE_ENCODER_TVDAC, "TVDAC" },
86}; 138};
87 139
88type_name_fn(encoder_type) 140static type_name_fn(encoder_type)
89 141
90struct type_name connector_status_names[] = { 142struct type_name connector_status_names[] = {
91 { DRM_MODE_CONNECTED, "connected" }, 143 { DRM_MODE_CONNECTED, "connected" },
@@ -93,7 +145,7 @@ struct type_name connector_status_names[] = {
93 { DRM_MODE_UNKNOWNCONNECTION, "unknown" }, 145 { DRM_MODE_UNKNOWNCONNECTION, "unknown" },
94}; 146};
95 147
96type_name_fn(connector_status) 148static type_name_fn(connector_status)
97 149
98struct type_name connector_type_names[] = { 150struct type_name connector_type_names[] = {
99 { DRM_MODE_CONNECTOR_Unknown, "unknown" }, 151 { DRM_MODE_CONNECTOR_Unknown, "unknown" },
@@ -106,18 +158,18 @@ struct type_name connector_type_names[] = {
106 { DRM_MODE_CONNECTOR_LVDS, "LVDS" }, 158 { DRM_MODE_CONNECTOR_LVDS, "LVDS" },
107 { DRM_MODE_CONNECTOR_Component, "component" }, 159 { DRM_MODE_CONNECTOR_Component, "component" },
108 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" }, 160 { DRM_MODE_CONNECTOR_9PinDIN, "9-pin DIN" },
109 { DRM_MODE_CONNECTOR_DisplayPort, "displayport" }, 161 { DRM_MODE_CONNECTOR_DisplayPort, "DP" },
110 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" }, 162 { DRM_MODE_CONNECTOR_HDMIA, "HDMI-A" },
111 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" }, 163 { DRM_MODE_CONNECTOR_HDMIB, "HDMI-B" },
112 { DRM_MODE_CONNECTOR_TV, "TV" }, 164 { DRM_MODE_CONNECTOR_TV, "TV" },
113 { DRM_MODE_CONNECTOR_eDP, "embedded displayport" }, 165 { DRM_MODE_CONNECTOR_eDP, "eDP" },
114}; 166};
115 167
116type_name_fn(connector_type) 168static type_name_fn(connector_type)
117 169
118#define bit_name_fn(res) \ 170#define bit_name_fn(res) \
119char * res##_str(int type) { \ 171const char * res##_str(int type) { \
120 int i; \ 172 unsigned int i; \
121 const char *sep = ""; \ 173 const char *sep = ""; \
122 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \ 174 for (i = 0; i < ARRAY_SIZE(res##_names); i++) { \
123 if (type & (1 << i)) { \ 175 if (type & (1 << i)) { \
@@ -138,7 +190,7 @@ static const char *mode_type_names[] = {
138 "driver", 190 "driver",
139}; 191};
140 192
141bit_name_fn(mode_type) 193static bit_name_fn(mode_type)
142 194
143static const char *mode_flag_names[] = { 195static const char *mode_flag_names[] = {
144 "phsync", 196 "phsync",
@@ -157,35 +209,31 @@ static const char *mode_flag_names[] = {
157 "clkdiv2" 209 "clkdiv2"
158}; 210};
159 211
160bit_name_fn(mode_flag) 212static bit_name_fn(mode_flag)
161 213
162void dump_encoders(void) 214static void dump_encoders(struct device *dev)
163{ 215{
164 drmModeEncoder *encoder; 216 drmModeEncoder *encoder;
165 int i; 217 int i;
166 218
167 printf("Encoders:\n"); 219 printf("Encoders:\n");
168 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n"); 220 printf("id\tcrtc\ttype\tpossible crtcs\tpossible clones\t\n");
169 for (i = 0; i < resources->count_encoders; i++) { 221 for (i = 0; i < dev->resources->res->count_encoders; i++) {
170 encoder = drmModeGetEncoder(fd, resources->encoders[i]); 222 encoder = dev->resources->encoders[i].encoder;
171 223 if (!encoder)
172 if (!encoder) {
173 fprintf(stderr, "could not get encoder %i: %s\n",
174 resources->encoders[i], strerror(errno));
175 continue; 224 continue;
176 } 225
177 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n", 226 printf("%d\t%d\t%s\t0x%08x\t0x%08x\n",
178 encoder->encoder_id, 227 encoder->encoder_id,
179 encoder->crtc_id, 228 encoder->crtc_id,
180 encoder_type_str(encoder->encoder_type), 229 encoder_type_str(encoder->encoder_type),
181 encoder->possible_crtcs, 230 encoder->possible_crtcs,
182 encoder->possible_clones); 231 encoder->possible_clones);
183 drmModeFreeEncoder(encoder);
184 } 232 }
185 printf("\n"); 233 printf("\n");
186} 234}
187 235
188void dump_mode(drmModeModeInfo *mode) 236static void dump_mode(drmModeModeInfo *mode)
189{ 237{
190 printf(" %s %d %d %d %d %d %d %d %d %d", 238 printf(" %s %d %d %d %d %d %d %d %d %d",
191 mode->name, 239 mode->name,
@@ -206,14 +254,13 @@ void dump_mode(drmModeModeInfo *mode)
206 printf("\n"); 254 printf("\n");
207} 255}
208 256
209static void 257static void dump_blob(struct device *dev, uint32_t blob_id)
210dump_blob(uint32_t blob_id)
211{ 258{
212 uint32_t i; 259 uint32_t i;
213 unsigned char *blob_data; 260 unsigned char *blob_data;
214 drmModePropertyBlobPtr blob; 261 drmModePropertyBlobPtr blob;
215 262
216 blob = drmModeGetPropertyBlob(fd, blob_id); 263 blob = drmModeGetPropertyBlob(dev->fd, blob_id);
217 if (!blob) 264 if (!blob)
218 return; 265 return;
219 266
@@ -229,14 +276,10 @@ dump_blob(uint32_t blob_id)
229 drmModeFreePropertyBlob(blob); 276 drmModeFreePropertyBlob(blob);
230} 277}
231 278
232static void 279static void dump_prop(struct device *dev, drmModePropertyPtr prop,
233dump_prop(uint32_t prop_id, uint64_t value) 280 uint32_t prop_id, uint64_t value)
234{ 281{
235 int i; 282 int i;
236 drmModePropertyPtr prop;
237
238 prop = drmModeGetProperty(fd, prop_id);
239
240 printf("\t%d", prop_id); 283 printf("\t%d", prop_id);
241 if (!prop) { 284 if (!prop) {
242 printf("\n"); 285 printf("\n");
@@ -286,7 +329,7 @@ dump_prop(uint32_t prop_id, uint64_t value)
286 if (prop->flags & DRM_MODE_PROP_BLOB) { 329 if (prop->flags & DRM_MODE_PROP_BLOB) {
287 printf("\t\tblobs:\n"); 330 printf("\t\tblobs:\n");
288 for (i = 0; i < prop->count_blobs; i++) 331 for (i = 0; i < prop->count_blobs; i++)
289 dump_blob(prop->blob_ids[i]); 332 dump_blob(dev, prop->blob_ids[i]);
290 printf("\n"); 333 printf("\n");
291 } else { 334 } else {
292 assert(prop->count_blobs == 0); 335 assert(prop->count_blobs == 0);
@@ -294,28 +337,22 @@ dump_prop(uint32_t prop_id, uint64_t value)
294 337
295 printf("\t\tvalue:"); 338 printf("\t\tvalue:");
296 if (prop->flags & DRM_MODE_PROP_BLOB) 339 if (prop->flags & DRM_MODE_PROP_BLOB)
297 dump_blob(value); 340 dump_blob(dev, value);
298 else 341 else
299 printf(" %"PRIu64"\n", value); 342 printf(" %"PRIu64"\n", value);
300
301 drmModeFreeProperty(prop);
302} 343}
303 344
304void dump_connectors(void) 345static void dump_connectors(struct device *dev)
305{ 346{
306 drmModeConnector *connector;
307 int i, j; 347 int i, j;
308 348
309 printf("Connectors:\n"); 349 printf("Connectors:\n");
310 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n"); 350 printf("id\tencoder\tstatus\t\ttype\tsize (mm)\tmodes\tencoders\n");
311 for (i = 0; i < resources->count_connectors; i++) { 351 for (i = 0; i < dev->resources->res->count_connectors; i++) {
312 connector = drmModeGetConnector(fd, resources->connectors[i]); 352 struct connector *_connector = &dev->resources->connectors[i];
313 353 drmModeConnector *connector = _connector->connector;
314 if (!connector) { 354 if (!connector)
315 fprintf(stderr, "could not get connector %i: %s\n",
316 resources->connectors[i], strerror(errno));
317 continue; 355 continue;
318 }
319 356
320 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t", 357 printf("%d\t%d\t%s\t%s\t%dx%d\t\t%d\t",
321 connector->connector_id, 358 connector->connector_id,
@@ -335,35 +372,32 @@ void dump_connectors(void)
335 "vss vse vtot)\n"); 372 "vss vse vtot)\n");
336 for (j = 0; j < connector->count_modes; j++) 373 for (j = 0; j < connector->count_modes; j++)
337 dump_mode(&connector->modes[j]); 374 dump_mode(&connector->modes[j]);
375 }
338 376
377 if (_connector->props) {
339 printf(" props:\n"); 378 printf(" props:\n");
340 for (j = 0; j < connector->count_props; j++) 379 for (j = 0; j < (int)_connector->props->count_props; j++)
341 dump_prop(connector->props[j], 380 dump_prop(dev, _connector->props_info[j],
342 connector->prop_values[j]); 381 _connector->props->props[j],
382 _connector->props->prop_values[j]);
343 } 383 }
344
345 drmModeFreeConnector(connector);
346 } 384 }
347 printf("\n"); 385 printf("\n");
348} 386}
349 387
350void dump_crtcs(void) 388static void dump_crtcs(struct device *dev)
351{ 389{
352 drmModeCrtc *crtc;
353 drmModeObjectPropertiesPtr props;
354 int i; 390 int i;
355 uint32_t j; 391 uint32_t j;
356 392
357 printf("CRTCs:\n"); 393 printf("CRTCs:\n");
358 printf("id\tfb\tpos\tsize\n"); 394 printf("id\tfb\tpos\tsize\n");
359 for (i = 0; i < resources->count_crtcs; i++) { 395 for (i = 0; i < dev->resources->res->count_crtcs; i++) {
360 crtc = drmModeGetCrtc(fd, resources->crtcs[i]); 396 struct crtc *_crtc = &dev->resources->crtcs[i];
361 397 drmModeCrtc *crtc = _crtc->crtc;
362 if (!crtc) { 398 if (!crtc)
363 fprintf(stderr, "could not get crtc %i: %s\n",
364 resources->crtcs[i], strerror(errno));
365 continue; 399 continue;
366 } 400
367 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n", 401 printf("%d\t%d\t(%d,%d)\t(%dx%d)\n",
368 crtc->crtc_id, 402 crtc->crtc_id,
369 crtc->buffer_id, 403 crtc->buffer_id,
@@ -371,77 +405,59 @@ void dump_crtcs(void)
371 crtc->width, crtc->height); 405 crtc->width, crtc->height);
372 dump_mode(&crtc->mode); 406 dump_mode(&crtc->mode);
373 407
374 printf(" props:\n"); 408 if (_crtc->props) {
375 props = drmModeObjectGetProperties(fd, crtc->crtc_id, 409 printf(" props:\n");
376 DRM_MODE_OBJECT_CRTC); 410 for (j = 0; j < _crtc->props->count_props; j++)
377 if (props) { 411 dump_prop(dev, _crtc->props_info[j],
378 for (j = 0; j < props->count_props; j++) 412 _crtc->props->props[j],
379 dump_prop(props->props[j], 413 _crtc->props->prop_values[j]);
380 props->prop_values[j]);
381 drmModeFreeObjectProperties(props);
382 } else { 414 } else {
383 printf("\tcould not get crtc properties: %s\n", 415 printf(" no properties found\n");
384 strerror(errno));
385 } 416 }
386
387 drmModeFreeCrtc(crtc);
388 } 417 }
389 printf("\n"); 418 printf("\n");
390} 419}
391 420
392void dump_framebuffers(void) 421static void dump_framebuffers(struct device *dev)
393{ 422{
394 drmModeFB *fb; 423 drmModeFB *fb;
395 int i; 424 int i;
396 425
397 printf("Frame buffers:\n"); 426 printf("Frame buffers:\n");
398 printf("id\tsize\tpitch\n"); 427 printf("id\tsize\tpitch\n");
399 for (i = 0; i < resources->count_fbs; i++) { 428 for (i = 0; i < dev->resources->res->count_fbs; i++) {
400 fb = drmModeGetFB(fd, resources->fbs[i]); 429 fb = dev->resources->fbs[i].fb;
401 430 if (!fb)
402 if (!fb) {
403 fprintf(stderr, "could not get fb %i: %s\n",
404 resources->fbs[i], strerror(errno));
405 continue; 431 continue;
406 } 432
407 printf("%u\t(%ux%u)\t%u\n", 433 printf("%u\t(%ux%u)\t%u\n",
408 fb->fb_id, 434 fb->fb_id,
409 fb->width, fb->height, 435 fb->width, fb->height,
410 fb->pitch); 436 fb->pitch);
411
412 drmModeFreeFB(fb);
413 } 437 }
414 printf("\n"); 438 printf("\n");
415} 439}
416 440
417static void dump_planes(void) 441static void dump_planes(struct device *dev)
418{ 442{
419 drmModeObjectPropertiesPtr props;
420 drmModePlaneRes *plane_resources;
421 drmModePlane *ovr;
422 unsigned int i, j; 443 unsigned int i, j;
423 444
424 plane_resources = drmModeGetPlaneResources(fd); 445 printf("Planes:\n");
425 if (!plane_resources) { 446 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\tpossible crtcs\n");
426 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 447
427 strerror(errno)); 448 if (!dev->resources->plane_res)
428 return; 449 return;
429 }
430 450
431 printf("Planes:\n"); 451 for (i = 0; i < dev->resources->plane_res->count_planes; i++) {
432 printf("id\tcrtc\tfb\tCRTC x,y\tx,y\tgamma size\n"); 452 struct plane *plane = &dev->resources->planes[i];
433 for (i = 0; i < plane_resources->count_planes; i++) { 453 drmModePlane *ovr = plane->plane;
434 ovr = drmModeGetPlane(fd, plane_resources->planes[i]); 454 if (!ovr)
435 if (!ovr) {
436 fprintf(stderr, "drmModeGetPlane failed: %s\n",
437 strerror(errno));
438 continue; 455 continue;
439 }
440 456
441 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%d\n", 457 printf("%d\t%d\t%d\t%d,%d\t\t%d,%d\t%-8d\t0x%08x\n",
442 ovr->plane_id, ovr->crtc_id, ovr->fb_id, 458 ovr->plane_id, ovr->crtc_id, ovr->fb_id,
443 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y, 459 ovr->crtc_x, ovr->crtc_y, ovr->x, ovr->y,
444 ovr->gamma_size); 460 ovr->gamma_size, ovr->possible_crtcs);
445 461
446 if (!ovr->count_formats) 462 if (!ovr->count_formats)
447 continue; 463 continue;
@@ -451,29 +467,217 @@ static void dump_planes(void)
451 printf(" %4.4s", (char *)&ovr->formats[j]); 467 printf(" %4.4s", (char *)&ovr->formats[j]);
452 printf("\n"); 468 printf("\n");
453 469
454 printf(" props:\n"); 470 if (plane->props) {
455 props = drmModeObjectGetProperties(fd, ovr->plane_id, 471 printf(" props:\n");
456 DRM_MODE_OBJECT_PLANE); 472 for (j = 0; j < plane->props->count_props; j++)
457 if (props) { 473 dump_prop(dev, plane->props_info[j],
458 for (j = 0; j < props->count_props; j++) 474 plane->props->props[j],
459 dump_prop(props->props[j], 475 plane->props->prop_values[j]);
460 props->prop_values[j]);
461 drmModeFreeObjectProperties(props);
462 } else { 476 } else {
463 printf("\tcould not get plane properties: %s\n", 477 printf(" no properties found\n");
464 strerror(errno));
465 } 478 }
466
467 drmModeFreePlane(ovr);
468 } 479 }
469 printf("\n"); 480 printf("\n");
470 481
471 drmModeFreePlaneResources(plane_resources);
472 return; 482 return;
473} 483}
474 484
485static void free_resources(struct resources *res)
486{
487 if (!res)
488 return;
489
490#define free_resource(_res, __res, type, Type) \
491 do { \
492 int i; \
493 if (!(_res)->type##s) \
494 break; \
495 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
496 if (!(_res)->type##s[i].type) \
497 break; \
498 drmModeFree##Type((_res)->type##s[i].type); \
499 } \
500 free((_res)->type##s); \
501 } while (0)
502
503#define free_properties(_res, __res, type) \
504 do { \
505 int i; \
506 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
507 drmModeFreeObjectProperties(res->type##s[i].props); \
508 free(res->type##s[i].props_info); \
509 } \
510 } while (0)
511
512 if (res->res) {
513 free_properties(res, res, crtc);
514
515 free_resource(res, res, crtc, Crtc);
516 free_resource(res, res, encoder, Encoder);
517 free_resource(res, res, connector, Connector);
518 free_resource(res, res, fb, FB);
519
520 drmModeFreeResources(res->res);
521 }
522
523 if (res->plane_res) {
524 free_properties(res, plane_res, plane);
525
526 free_resource(res, plane_res, plane, Plane);
527
528 drmModeFreePlaneResources(res->plane_res);
529 }
530
531 free(res);
532}
533
534static struct resources *get_resources(struct device *dev)
535{
536 struct resources *res;
537 int i;
538
539 res = malloc(sizeof *res);
540 if (res == 0)
541 return NULL;
542
543 memset(res, 0, sizeof *res);
544
545 res->res = drmModeGetResources(dev->fd);
546 if (!res->res) {
547 fprintf(stderr, "drmModeGetResources failed: %s\n",
548 strerror(errno));
549 goto error;
550 }
551
552 res->crtcs = malloc(res->res->count_crtcs * sizeof *res->crtcs);
553 res->encoders = malloc(res->res->count_encoders * sizeof *res->encoders);
554 res->connectors = malloc(res->res->count_connectors * sizeof *res->connectors);
555 res->fbs = malloc(res->res->count_fbs * sizeof *res->fbs);
556
557 if (!res->crtcs || !res->encoders || !res->connectors || !res->fbs)
558 goto error;
559
560 memset(res->crtcs , 0, res->res->count_crtcs * sizeof *res->crtcs);
561 memset(res->encoders, 0, res->res->count_encoders * sizeof *res->encoders);
562 memset(res->connectors, 0, res->res->count_connectors * sizeof *res->connectors);
563 memset(res->fbs, 0, res->res->count_fbs * sizeof *res->fbs);
564
565#define get_resource(_res, __res, type, Type) \
566 do { \
567 int i; \
568 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
569 (_res)->type##s[i].type = \
570 drmModeGet##Type(dev->fd, (_res)->__res->type##s[i]); \
571 if (!(_res)->type##s[i].type) \
572 fprintf(stderr, "could not get %s %i: %s\n", \
573 #type, (_res)->__res->type##s[i], \
574 strerror(errno)); \
575 } \
576 } while (0)
577
578 get_resource(res, res, crtc, Crtc);
579 get_resource(res, res, encoder, Encoder);
580 get_resource(res, res, connector, Connector);
581 get_resource(res, res, fb, FB);
582
583#define get_properties(_res, __res, type, Type) \
584 do { \
585 int i; \
586 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
587 struct type *obj = &res->type##s[i]; \
588 unsigned int j; \
589 obj->props = \
590 drmModeObjectGetProperties(dev->fd, obj->type->type##_id, \
591 DRM_MODE_OBJECT_##Type); \
592 if (!obj->props) { \
593 fprintf(stderr, \
594 "could not get %s %i properties: %s\n", \
595 #type, obj->type->type##_id, \
596 strerror(errno)); \
597 continue; \
598 } \
599 obj->props_info = malloc(obj->props->count_props * \
600 sizeof *obj->props_info); \
601 if (!obj->props_info) \
602 continue; \
603 for (j = 0; j < obj->props->count_props; ++j) \
604 obj->props_info[j] = \
605 drmModeGetProperty(dev->fd, obj->props->props[j]); \
606 } \
607 } while (0)
608
609 get_properties(res, res, crtc, CRTC);
610 get_properties(res, res, connector, CONNECTOR);
611
612 for (i = 0; i < res->res->count_crtcs; ++i)
613 res->crtcs[i].mode = &res->crtcs[i].crtc->mode;
614
615 res->plane_res = drmModeGetPlaneResources(dev->fd);
616 if (!res->plane_res) {
617 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n",
618 strerror(errno));
619 return res;
620 }
621
622 res->planes = malloc(res->plane_res->count_planes * sizeof *res->planes);
623 if (!res->planes)
624 goto error;
625
626 memset(res->planes, 0, res->plane_res->count_planes * sizeof *res->planes);
627
628 get_resource(res, plane_res, plane, Plane);
629 get_properties(res, plane_res, plane, PLANE);
630
631 return res;
632
633error:
634 free_resources(res);
635 return NULL;
636}
637
638static int get_crtc_index(struct device *dev, uint32_t id)
639{
640 int i;
641
642 for (i = 0; i < dev->resources->res->count_crtcs; ++i) {
643 drmModeCrtc *crtc = dev->resources->crtcs[i].crtc;
644 if (crtc && crtc->crtc_id == id)
645 return i;
646 }
647
648 return -1;
649}
650
651static drmModeConnector *get_connector_by_id(struct device *dev, uint32_t id)
652{
653 drmModeConnector *connector;
654 int i;
655
656 for (i = 0; i < dev->resources->res->count_connectors; i++) {
657 connector = dev->resources->connectors[i].connector;
658 if (connector && connector->connector_id == id)
659 return connector;
660 }
661
662 return NULL;
663}
664
665static drmModeEncoder *get_encoder_by_id(struct device *dev, uint32_t id)
666{
667 drmModeEncoder *encoder;
668 int i;
669
670 for (i = 0; i < dev->resources->res->count_encoders; i++) {
671 encoder = dev->resources->encoders[i].encoder;
672 if (encoder && encoder->encoder_id == id)
673 return encoder;
674 }
675
676 return NULL;
677}
678
475/* ----------------------------------------------------------------------------- 679/* -----------------------------------------------------------------------------
476 * Connectors and planes 680 * Pipes and planes
477 */ 681 */
478 682
479/* 683/*
@@ -483,198 +687,331 @@ static void dump_planes(void)
483 * Then you need to find the encoder attached to that connector so you 687 * Then you need to find the encoder attached to that connector so you
484 * can bind it with a free crtc. 688 * can bind it with a free crtc.
485 */ 689 */
486struct connector { 690struct pipe_arg {
487 uint32_t id; 691 uint32_t *con_ids;
692 unsigned int num_cons;
693 uint32_t crtc_id;
488 char mode_str[64]; 694 char mode_str[64];
489 char format_str[5]; 695 char format_str[5];
696 unsigned int vrefresh;
490 unsigned int fourcc; 697 unsigned int fourcc;
491 drmModeModeInfo *mode; 698 drmModeModeInfo *mode;
492 drmModeEncoder *encoder; 699 struct crtc *crtc;
493 int crtc;
494 int pipe;
495 unsigned int fb_id[2], current_fb_id; 700 unsigned int fb_id[2], current_fb_id;
496 struct timeval start; 701 struct timeval start;
497 702
498 int swap_count; 703 int swap_count;
499}; 704};
500 705
501struct plane { 706struct plane_arg {
502 uint32_t con_id; /* the id of connector to bind to */ 707 uint32_t crtc_id; /* the id of CRTC to bind to */
708 bool has_position;
709 int32_t x, y;
503 uint32_t w, h; 710 uint32_t w, h;
711 double scale;
504 unsigned int fb_id; 712 unsigned int fb_id;
505 char format_str[5]; /* need to leave room for terminating \0 */ 713 char format_str[5]; /* need to leave room for terminating \0 */
506 unsigned int fourcc; 714 unsigned int fourcc;
507}; 715};
508 716
509static void 717static drmModeModeInfo *
510connector_find_mode(struct connector *c) 718connector_find_mode(struct device *dev, uint32_t con_id, const char *mode_str,
719 const unsigned int vrefresh)
511{ 720{
512 drmModeConnector *connector; 721 drmModeConnector *connector;
513 int i, j; 722 drmModeModeInfo *mode;
514 723 int i;
515 /* First, find the connector & mode */
516 c->mode = NULL;
517 for (i = 0; i < resources->count_connectors; i++) {
518 connector = drmModeGetConnector(fd, resources->connectors[i]);
519 724
520 if (!connector) { 725 connector = get_connector_by_id(dev, con_id);
521 fprintf(stderr, "could not get connector %i: %s\n", 726 if (!connector || !connector->count_modes)
522 resources->connectors[i], strerror(errno)); 727 return NULL;
523 drmModeFreeConnector(connector); 728
524 continue; 729 for (i = 0; i < connector->count_modes; i++) {
730 mode = &connector->modes[i];
731 if (!strcmp(mode->name, mode_str)) {
732 /* If the vertical refresh frequency is not specified then return the
733 * first mode that match with the name. Else, return the mode that match
734 * the name and the specified vertical refresh frequency.
735 */
736 if (vrefresh == 0)
737 return mode;
738 else if (mode->vrefresh == vrefresh)
739 return mode;
525 } 740 }
741 }
526 742
527 if (!connector->count_modes) { 743 return NULL;
528 drmModeFreeConnector(connector); 744}
529 continue;
530 }
531 745
532 if (connector->connector_id != c->id) { 746static struct crtc *pipe_find_crtc(struct device *dev, struct pipe_arg *pipe)
533 drmModeFreeConnector(connector); 747{
534 continue; 748 uint32_t possible_crtcs = ~0;
749 uint32_t active_crtcs = 0;
750 unsigned int crtc_idx;
751 unsigned int i;
752 int j;
753
754 for (i = 0; i < pipe->num_cons; ++i) {
755 uint32_t crtcs_for_connector = 0;
756 drmModeConnector *connector;
757 drmModeEncoder *encoder;
758 int idx;
759
760 connector = get_connector_by_id(dev, pipe->con_ids[i]);
761 if (!connector)
762 return NULL;
763
764 for (j = 0; j < connector->count_encoders; ++j) {
765 encoder = get_encoder_by_id(dev, connector->encoders[j]);
766 if (!encoder)
767 continue;
768
769 crtcs_for_connector |= encoder->possible_crtcs;
770
771 idx = get_crtc_index(dev, encoder->crtc_id);
772 if (idx >= 0)
773 active_crtcs |= 1 << idx;
535 } 774 }
536 775
537 for (j = 0; j < connector->count_modes; j++) { 776 possible_crtcs &= crtcs_for_connector;
538 c->mode = &connector->modes[j]; 777 }
539 if (!strcmp(c->mode->name, c->mode_str)) 778
540 break; 779 if (!possible_crtcs)
780 return NULL;
781
782 /* Return the first possible and active CRTC if one exists, or the first
783 * possible CRTC otherwise.
784 */
785 if (possible_crtcs & active_crtcs)
786 crtc_idx = ffs(possible_crtcs & active_crtcs);
787 else
788 crtc_idx = ffs(possible_crtcs);
789
790 return &dev->resources->crtcs[crtc_idx - 1];
791}
792
793static int pipe_find_crtc_and_mode(struct device *dev, struct pipe_arg *pipe)
794{
795 drmModeModeInfo *mode = NULL;
796 int i;
797
798 pipe->mode = NULL;
799
800 for (i = 0; i < (int)pipe->num_cons; i++) {
801 mode = connector_find_mode(dev, pipe->con_ids[i],
802 pipe->mode_str, pipe->vrefresh);
803 if (mode == NULL) {
804 fprintf(stderr,
805 "failed to find mode \"%s\" for connector %u\n",
806 pipe->mode_str, pipe->con_ids[i]);
807 return -EINVAL;
541 } 808 }
809 }
542 810
543 /* Found it, break out */ 811 /* If the CRTC ID was specified, get the corresponding CRTC. Otherwise
544 if (c->mode) 812 * locate a CRTC that can be attached to all the connectors.
545 break; 813 */
814 if (pipe->crtc_id != (uint32_t)-1) {
815 for (i = 0; i < dev->resources->res->count_crtcs; i++) {
816 struct crtc *crtc = &dev->resources->crtcs[i];
546 817
547 drmModeFreeConnector(connector); 818 if (pipe->crtc_id == crtc->crtc->crtc_id) {
819 pipe->crtc = crtc;
820 break;
821 }
822 }
823 } else {
824 pipe->crtc = pipe_find_crtc(dev, pipe);
548 } 825 }
549 826
550 if (!c->mode) { 827 if (!pipe->crtc) {
551 fprintf(stderr, "failed to find mode \"%s\"\n", c->mode_str); 828 fprintf(stderr, "failed to find CRTC for pipe\n");
552 return; 829 return -EINVAL;
553 } 830 }
554 831
555 /* Now get the encoder */ 832 pipe->mode = mode;
556 for (i = 0; i < resources->count_encoders; i++) { 833 pipe->crtc->mode = mode;
557 c->encoder = drmModeGetEncoder(fd, resources->encoders[i]);
558 834
559 if (!c->encoder) { 835 return 0;
560 fprintf(stderr, "could not get encoder %i: %s\n", 836}
561 resources->encoders[i], strerror(errno));
562 drmModeFreeEncoder(c->encoder);
563 continue;
564 }
565 837
566 if (c->encoder->encoder_id == connector->encoder_id) 838/* -----------------------------------------------------------------------------
567 break; 839 * Properties
840 */
841
842struct property_arg {
843 uint32_t obj_id;
844 uint32_t obj_type;
845 char name[DRM_PROP_NAME_LEN+1];
846 uint32_t prop_id;
847 uint64_t value;
848};
849
850static void set_property(struct device *dev, struct property_arg *p)
851{
852 drmModeObjectProperties *props = NULL;
853 drmModePropertyRes **props_info = NULL;
854 const char *obj_type;
855 int ret;
856 int i;
568 857
569 drmModeFreeEncoder(c->encoder); 858 p->obj_type = 0;
859 p->prop_id = 0;
860
861#define find_object(_res, __res, type, Type) \
862 do { \
863 for (i = 0; i < (int)(_res)->__res->count_##type##s; ++i) { \
864 struct type *obj = &(_res)->type##s[i]; \
865 if (obj->type->type##_id != p->obj_id) \
866 continue; \
867 p->obj_type = DRM_MODE_OBJECT_##Type; \
868 obj_type = #Type; \
869 props = obj->props; \
870 props_info = obj->props_info; \
871 } \
872 } while(0) \
873
874 find_object(dev->resources, res, crtc, CRTC);
875 if (p->obj_type == 0)
876 find_object(dev->resources, res, connector, CONNECTOR);
877 if (p->obj_type == 0)
878 find_object(dev->resources, plane_res, plane, PLANE);
879 if (p->obj_type == 0) {
880 fprintf(stderr, "Object %i not found, can't set property\n",
881 p->obj_id);
882 return;
570 } 883 }
571 884
572 if (c->crtc == -1) 885 if (!props) {
573 c->crtc = c->encoder->crtc_id; 886 fprintf(stderr, "%s %i has no properties\n",
887 obj_type, p->obj_id);
888 return;
889 }
574 890
575 /* and figure out which crtc index it is: */ 891 for (i = 0; i < (int)props->count_props; ++i) {
576 for (i = 0; i < resources->count_crtcs; i++) { 892 if (!props_info[i])
577 if (c->crtc == resources->crtcs[i]) { 893 continue;
578 c->pipe = i; 894 if (strcmp(props_info[i]->name, p->name) == 0)
579 break; 895 break;
580 }
581 } 896 }
582 897
898 if (i == (int)props->count_props) {
899 fprintf(stderr, "%s %i has no %s property\n",
900 obj_type, p->obj_id, p->name);
901 return;
902 }
903
904 p->prop_id = props->props[i];
905
906 ret = drmModeObjectSetProperty(dev->fd, p->obj_id, p->obj_type,
907 p->prop_id, p->value);
908 if (ret < 0)
909 fprintf(stderr, "failed to set %s %i property %s to %" PRIu64 ": %s\n",
910 obj_type, p->obj_id, p->name, p->value, strerror(errno));
583} 911}
584 912
585/* -------------------------------------------------------------------------- */ 913/* -------------------------------------------------------------------------- */
586 914
587void 915static void
588page_flip_handler(int fd, unsigned int frame, 916page_flip_handler(int fd, unsigned int frame,
589 unsigned int sec, unsigned int usec, void *data) 917 unsigned int sec, unsigned int usec, void *data)
590{ 918{
591 struct connector *c; 919 struct pipe_arg *pipe;
592 unsigned int new_fb_id; 920 unsigned int new_fb_id;
593 struct timeval end; 921 struct timeval end;
594 double t; 922 double t;
595 923
596 c = data; 924 pipe = data;
597 if (c->current_fb_id == c->fb_id[0]) 925 if (pipe->current_fb_id == pipe->fb_id[0])
598 new_fb_id = c->fb_id[1]; 926 new_fb_id = pipe->fb_id[1];
599 else 927 else
600 new_fb_id = c->fb_id[0]; 928 new_fb_id = pipe->fb_id[0];
601 929
602 drmModePageFlip(fd, c->crtc, new_fb_id, 930 drmModePageFlip(fd, pipe->crtc->crtc->crtc_id, new_fb_id,
603 DRM_MODE_PAGE_FLIP_EVENT, c); 931 DRM_MODE_PAGE_FLIP_EVENT, pipe);
604 c->current_fb_id = new_fb_id; 932 pipe->current_fb_id = new_fb_id;
605 c->swap_count++; 933 pipe->swap_count++;
606 if (c->swap_count == 60) { 934 if (pipe->swap_count == 60) {
607 gettimeofday(&end, NULL); 935 gettimeofday(&end, NULL);
608 t = end.tv_sec + end.tv_usec * 1e-6 - 936 t = end.tv_sec + end.tv_usec * 1e-6 -
609 (c->start.tv_sec + c->start.tv_usec * 1e-6); 937 (pipe->start.tv_sec + pipe->start.tv_usec * 1e-6);
610 fprintf(stderr, "freq: %.02fHz\n", c->swap_count / t); 938 fprintf(stderr, "freq: %.02fHz\n", pipe->swap_count / t);
611 c->swap_count = 0; 939 pipe->swap_count = 0;
612 c->start = end; 940 pipe->start = end;
613 } 941 }
614} 942}
615 943
616static int 944static int set_plane(struct device *dev, struct plane_arg *p)
617set_plane(struct kms_driver *kms, struct connector *c, struct plane *p)
618{ 945{
619 drmModePlaneRes *plane_resources;
620 drmModePlane *ovr; 946 drmModePlane *ovr;
621 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 947 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
622 uint32_t plane_id = 0; 948 uint32_t plane_id = 0;
623 struct kms_bo *plane_bo; 949 struct kms_bo *plane_bo;
624 uint32_t plane_flags = 0; 950 uint32_t plane_flags = 0;
625 int ret, crtc_x, crtc_y, crtc_w, crtc_h; 951 int crtc_x, crtc_y, crtc_w, crtc_h;
952 struct crtc *crtc = NULL;
953 unsigned int pipe;
626 unsigned int i; 954 unsigned int i;
627 955
628 /* find an unused plane which can be connected to our crtc */ 956 /* Find an unused plane which can be connected to our CRTC. Find the
629 plane_resources = drmModeGetPlaneResources(fd); 957 * CRTC index first, then iterate over available planes.
630 if (!plane_resources) { 958 */
631 fprintf(stderr, "drmModeGetPlaneResources failed: %s\n", 959 for (i = 0; i < (unsigned int)dev->resources->res->count_crtcs; i++) {
632 strerror(errno)); 960 if (p->crtc_id == dev->resources->res->crtcs[i]) {
961 crtc = &dev->resources->crtcs[i];
962 pipe = i;
963 break;
964 }
965 }
966
967 if (!crtc) {
968 fprintf(stderr, "CRTC %u not found\n", p->crtc_id);
633 return -1; 969 return -1;
634 } 970 }
635 971
636 for (i = 0; i < plane_resources->count_planes && !plane_id; i++) { 972 for (i = 0; i < dev->resources->plane_res->count_planes && !plane_id; i++) {
637 ovr = drmModeGetPlane(fd, plane_resources->planes[i]); 973 ovr = dev->resources->planes[i].plane;
638 if (!ovr) { 974 if (!ovr)
639 fprintf(stderr, "drmModeGetPlane failed: %s\n", 975 continue;
640 strerror(errno));
641 return -1;
642 }
643 976
644 if ((ovr->possible_crtcs & (1 << c->pipe)) && !ovr->crtc_id) 977 if ((ovr->possible_crtcs & (1 << pipe)) && !ovr->crtc_id)
645 plane_id = ovr->plane_id; 978 plane_id = ovr->plane_id;
646
647 drmModeFreePlane(ovr);
648 } 979 }
649 980
650 fprintf(stderr, "testing %dx%d@%s overlay plane\n",
651 p->w, p->h, p->format_str);
652
653 if (!plane_id) { 981 if (!plane_id) {
654 fprintf(stderr, "failed to find plane!\n"); 982 fprintf(stderr, "no unused plane available for CRTC %u\n",
983 crtc->crtc->crtc_id);
655 return -1; 984 return -1;
656 } 985 }
657 986
658 plane_bo = create_test_buffer(kms, p->fourcc, p->w, p->h, handles, 987 fprintf(stderr, "testing %dx%d@%s overlay plane %u\n",
988 p->w, p->h, p->format_str, plane_id);
989
990 plane_bo = create_test_buffer(dev->kms, p->fourcc, p->w, p->h, handles,
659 pitches, offsets, PATTERN_TILES); 991 pitches, offsets, PATTERN_TILES);
660 if (plane_bo == NULL) 992 if (plane_bo == NULL)
661 return -1; 993 return -1;
662 994
663 /* just use single plane format for now.. */ 995 /* just use single plane format for now.. */
664 if (drmModeAddFB2(fd, p->w, p->h, p->fourcc, 996 if (drmModeAddFB2(dev->fd, p->w, p->h, p->fourcc,
665 handles, pitches, offsets, &p->fb_id, plane_flags)) { 997 handles, pitches, offsets, &p->fb_id, plane_flags)) {
666 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 998 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
667 return -1; 999 return -1;
668 } 1000 }
669 1001
670 /* ok, boring.. but for now put in middle of screen: */ 1002 crtc_w = p->w * p->scale;
671 crtc_x = c->mode->hdisplay / 3; 1003 crtc_h = p->h * p->scale;
672 crtc_y = c->mode->vdisplay / 3; 1004 if (!p->has_position) {
673 crtc_w = crtc_x; 1005 /* Default to the middle of the screen */
674 crtc_h = crtc_y; 1006 crtc_x = (crtc->mode->hdisplay - crtc_w) / 2;
1007 crtc_y = (crtc->mode->vdisplay - crtc_h) / 2;
1008 } else {
1009 crtc_x = p->x;
1010 crtc_y = p->y;
1011 }
675 1012
676 /* note src coords (last 4 args) are in Q16 format */ 1013 /* note src coords (last 4 args) are in Q16 format */
677 if (drmModeSetPlane(fd, plane_id, c->crtc, p->fb_id, 1014 if (drmModeSetPlane(dev->fd, plane_id, crtc->crtc->crtc_id, p->fb_id,
678 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h, 1015 plane_flags, crtc_x, crtc_y, crtc_w, crtc_h,
679 0, 0, p->w << 16, p->h << 16)) { 1016 0, 0, p->w << 16, p->h << 16)) {
680 fprintf(stderr, "failed to enable plane: %s\n", 1017 fprintf(stderr, "failed to enable plane: %s\n",
@@ -682,88 +1019,108 @@ set_plane(struct kms_driver *kms, struct connector *c, struct plane *p)
682 return -1; 1019 return -1;
683 } 1020 }
684 1021
1022 ovr->crtc_id = crtc->crtc->crtc_id;
1023
685 return 0; 1024 return 0;
686} 1025}
687 1026
688static void 1027static void set_mode(struct device *dev, struct pipe_arg *pipes, unsigned int count)
689set_mode(struct connector *c, int count, struct plane *p, int plane_count,
690 int page_flip)
691{ 1028{
692 struct kms_driver *kms;
693 struct kms_bo *bo, *other_bo;
694 unsigned int fb_id, other_fb_id;
695 int i, j, ret, width, height, x;
696 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */ 1029 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
697 drmEventContext evctx; 1030 unsigned int fb_id;
1031 struct kms_bo *bo;
1032 unsigned int i;
1033 unsigned int j;
1034 int ret, x;
1035
1036 dev->mode.width = 0;
1037 dev->mode.height = 0;
698 1038
699 width = 0;
700 height = 0;
701 for (i = 0; i < count; i++) { 1039 for (i = 0; i < count; i++) {
702 connector_find_mode(&c[i]); 1040 struct pipe_arg *pipe = &pipes[i];
703 if (c[i].mode == NULL) 1041
1042 ret = pipe_find_crtc_and_mode(dev, pipe);
1043 if (ret < 0)
704 continue; 1044 continue;
705 width += c[i].mode->hdisplay;
706 if (height < c[i].mode->vdisplay)
707 height = c[i].mode->vdisplay;
708 }
709 1045
710 ret = kms_create(fd, &kms); 1046 dev->mode.width += pipe->mode->hdisplay;
711 if (ret) { 1047 if (dev->mode.height < pipe->mode->vdisplay)
712 fprintf(stderr, "failed to create kms driver: %s\n", 1048 dev->mode.height = pipe->mode->vdisplay;
713 strerror(-ret));
714 return;
715 } 1049 }
716 1050
717 bo = create_test_buffer(kms, c->fourcc, width, height, handles, 1051 bo = create_test_buffer(dev->kms, pipes[0].fourcc,
718 pitches, offsets, PATTERN_SMPTE); 1052 dev->mode.width, dev->mode.height,
1053 handles, pitches, offsets, PATTERN_SMPTE);
719 if (bo == NULL) 1054 if (bo == NULL)
720 return; 1055 return;
721 1056
722 ret = drmModeAddFB2(fd, width, height, c->fourcc, 1057 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
723 handles, pitches, offsets, &fb_id, 0); 1058 pipes[0].fourcc, handles, pitches, offsets, &fb_id, 0);
724 if (ret) { 1059 if (ret) {
725 fprintf(stderr, "failed to add fb (%ux%u): %s\n", 1060 fprintf(stderr, "failed to add fb (%ux%u): %s\n",
726 width, height, strerror(errno)); 1061 dev->mode.width, dev->mode.height, strerror(errno));
727 return; 1062 return;
728 } 1063 }
729 1064
730 x = 0; 1065 x = 0;
731 for (i = 0; i < count; i++) { 1066 for (i = 0; i < count; i++) {
732 if (c[i].mode == NULL) 1067 struct pipe_arg *pipe = &pipes[i];
1068
1069 if (pipe->mode == NULL)
733 continue; 1070 continue;
734 1071
735 printf("setting mode %s@%s on connector %d, crtc %d\n", 1072 printf("setting mode %s-%dHz@%s on connectors ",
736 c[i].mode_str, c[i].format_str, c[i].id, c[i].crtc); 1073 pipe->mode_str, pipe->mode->vrefresh, pipe->format_str);
1074 for (j = 0; j < pipe->num_cons; ++j)
1075 printf("%u, ", pipe->con_ids[j]);
1076 printf("crtc %d\n", pipe->crtc->crtc->crtc_id);
737 1077
738 ret = drmModeSetCrtc(fd, c[i].crtc, fb_id, x, 0, 1078 ret = drmModeSetCrtc(dev->fd, pipe->crtc->crtc->crtc_id, fb_id,
739 &c[i].id, 1, c[i].mode); 1079 x, 0, pipe->con_ids, pipe->num_cons,
1080 pipe->mode);
740 1081
741 /* XXX: Actually check if this is needed */ 1082 /* XXX: Actually check if this is needed */
742 drmModeDirtyFB(fd, fb_id, NULL, 0); 1083 drmModeDirtyFB(dev->fd, fb_id, NULL, 0);
743 1084
744 x += c[i].mode->hdisplay; 1085 x += pipe->mode->hdisplay;
745 1086
746 if (ret) { 1087 if (ret) {
747 fprintf(stderr, "failed to set mode: %s\n", strerror(errno)); 1088 fprintf(stderr, "failed to set mode: %s\n", strerror(errno));
748 return; 1089 return;
749 } 1090 }
750
751 /* if we have a plane/overlay to show, set that up now: */
752 for (j = 0; j < plane_count; j++)
753 if (p[j].con_id == c[i].id)
754 if (set_plane(kms, &c[i], &p[j]))
755 return;
756 } 1091 }
757 1092
758 if (!page_flip) 1093 dev->mode.bo = bo;
759 return; 1094 dev->mode.fb_id = fb_id;
760 1095}
761 other_bo = create_test_buffer(kms, c->fourcc, width, height, handles, 1096
762 pitches, offsets, PATTERN_PLAIN); 1097static void set_planes(struct device *dev, struct plane_arg *p, unsigned int count)
1098{
1099 unsigned int i;
1100
1101 /* set up planes/overlays */
1102 for (i = 0; i < count; i++)
1103 if (set_plane(dev, &p[i]))
1104 return;
1105}
1106
1107static void test_page_flip(struct device *dev, struct pipe_arg *pipes, unsigned int count)
1108{
1109 uint32_t handles[4], pitches[4], offsets[4] = {0}; /* we only use [0] */
1110 unsigned int other_fb_id;
1111 struct kms_bo *other_bo;
1112 drmEventContext evctx;
1113 unsigned int i;
1114 int ret;
1115
1116 other_bo = create_test_buffer(dev->kms, pipes[0].fourcc,
1117 dev->mode.width, dev->mode.height,
1118 handles, pitches, offsets, PATTERN_PLAIN);
763 if (other_bo == NULL) 1119 if (other_bo == NULL)
764 return; 1120 return;
765 1121
766 ret = drmModeAddFB2(fd, width, height, c->fourcc, handles, pitches, offsets, 1122 ret = drmModeAddFB2(dev->fd, dev->mode.width, dev->mode.height,
1123 pipes[0].fourcc, handles, pitches, offsets,
767 &other_fb_id, 0); 1124 &other_fb_id, 0);
768 if (ret) { 1125 if (ret) {
769 fprintf(stderr, "failed to add fb: %s\n", strerror(errno)); 1126 fprintf(stderr, "failed to add fb: %s\n", strerror(errno));
@@ -771,20 +1128,23 @@ set_mode(struct connector *c, int count, struct plane *p, int plane_count,
771 } 1128 }
772 1129
773 for (i = 0; i < count; i++) { 1130 for (i = 0; i < count; i++) {
774 if (c[i].mode == NULL) 1131 struct pipe_arg *pipe = &pipes[i];
1132
1133 if (pipe->mode == NULL)
775 continue; 1134 continue;
776 1135
777 ret = drmModePageFlip(fd, c[i].crtc, other_fb_id, 1136 ret = drmModePageFlip(dev->fd, pipe->crtc->crtc->crtc_id,
778 DRM_MODE_PAGE_FLIP_EVENT, &c[i]); 1137 other_fb_id, DRM_MODE_PAGE_FLIP_EVENT,
1138 pipe);
779 if (ret) { 1139 if (ret) {
780 fprintf(stderr, "failed to page flip: %s\n", strerror(errno)); 1140 fprintf(stderr, "failed to page flip: %s\n", strerror(errno));
781 return; 1141 return;
782 } 1142 }
783 gettimeofday(&c[i].start, NULL); 1143 gettimeofday(&pipe->start, NULL);
784 c[i].swap_count = 0; 1144 pipe->swap_count = 0;
785 c[i].fb_id[0] = fb_id; 1145 pipe->fb_id[0] = dev->mode.fb_id;
786 c[i].fb_id[1] = other_fb_id; 1146 pipe->fb_id[1] = other_fb_id;
787 c[i].current_fb_id = other_fb_id; 1147 pipe->current_fb_id = other_fb_id;
788 } 1148 }
789 1149
790 memset(&evctx, 0, sizeof evctx); 1150 memset(&evctx, 0, sizeof evctx);
@@ -815,8 +1175,8 @@ set_mode(struct connector *c, int count, struct plane *p, int plane_count,
815 1175
816 FD_ZERO(&fds); 1176 FD_ZERO(&fds);
817 FD_SET(0, &fds); 1177 FD_SET(0, &fds);
818 FD_SET(fd, &fds); 1178 FD_SET(dev->fd, &fds);
819 ret = select(fd + 1, &fds, NULL, NULL, &timeout); 1179 ret = select(dev->fd + 1, &fds, NULL, NULL, &timeout);
820 1180
821 if (ret <= 0) { 1181 if (ret <= 0) {
822 fprintf(stderr, "select timed out or error (ret %d)\n", 1182 fprintf(stderr, "select timed out or error (ret %d)\n",
@@ -827,18 +1187,12 @@ set_mode(struct connector *c, int count, struct plane *p, int plane_count,
827 } 1187 }
828#endif 1188#endif
829 1189
830 drmHandleEvent(fd, &evctx); 1190 drmHandleEvent(dev->fd, &evctx);
831 } 1191 }
832 1192
833 kms_bo_destroy(&bo);
834 kms_bo_destroy(&other_bo); 1193 kms_bo_destroy(&other_bo);
835 kms_destroy(&kms);
836} 1194}
837 1195
838extern char *optarg;
839extern int optind, opterr, optopt;
840static char optstr[] = "ecpmfs:P:v";
841
842#define min(a, b) ((a) < (b) ? (a) : (b)) 1196#define min(a, b) ((a) < (b) ? (a) : (b))
843 1197
844static char * 1198static char *
@@ -851,78 +1205,166 @@ strchrnul (const char *s, int c_in)
851 return (char *) s; 1205 return (char *) s;
852} 1206}
853 1207
854static int parse_connector(struct connector *c, const char *arg) 1208static int parse_connector(struct pipe_arg *pipe, const char *arg)
855{ 1209{
856 unsigned int len; 1210 unsigned int len;
1211 unsigned int i;
857 const char *p; 1212 const char *p;
858 char *endp; 1213 char *endp;
859 1214
860 c->crtc = -1; 1215 pipe->vrefresh = 0;
861 strcpy(c->format_str, "XR24"); 1216 pipe->crtc_id = (uint32_t)-1;
1217 strcpy(pipe->format_str, "XR24");
1218
1219 /* Count the number of connectors and allocate them. */
1220 pipe->num_cons = 1;
1221 for (p = arg; isdigit(*p) || *p == ','; ++p) {
1222 if (*p == ',')
1223 pipe->num_cons++;
1224 }
1225
1226 pipe->con_ids = malloc(pipe->num_cons * sizeof *pipe->con_ids);
1227 if (pipe->con_ids == NULL)
1228 return -1;
1229
1230 /* Parse the connectors. */
1231 for (i = 0, p = arg; i < pipe->num_cons; ++i, p = endp + 1) {
1232 pipe->con_ids[i] = strtoul(p, &endp, 10);
1233 if (*endp != ',')
1234 break;
1235 }
1236
1237 if (i != pipe->num_cons - 1)
1238 return -1;
862 1239
863 c->id = strtoul(arg, &endp, 10); 1240 /* Parse the remaining parameters. */
864 if (*endp == '@') { 1241 if (*endp == '@') {
865 arg = endp + 1; 1242 arg = endp + 1;
866 c->crtc = strtoul(arg, &endp, 10); 1243 pipe->crtc_id = strtoul(arg, &endp, 10);
867 } 1244 }
868 if (*endp != ':') 1245 if (*endp != ':')
869 return -1; 1246 return -1;
870 1247
871 arg = endp + 1; 1248 arg = endp + 1;
872 1249
873 p = strchrnul(arg, '@'); 1250 /* Search for the vertical refresh or the format. */
874 len = min(sizeof c->mode_str - 1, p - arg); 1251 p = strpbrk(arg, "-@");
875 strncpy(c->mode_str, arg, len); 1252 if (p == NULL)
876 c->mode_str[len] = '\0'; 1253 p = arg + strlen(arg);
1254 len = min(sizeof pipe->mode_str - 1, (unsigned int)(p - arg));
1255 strncpy(pipe->mode_str, arg, len);
1256 pipe->mode_str[len] = '\0';
1257
1258 if (*p == '-') {
1259 pipe->vrefresh = strtoul(p + 1, &endp, 10);
1260 p = endp;
1261 }
877 1262
878 if (*p == '@') { 1263 if (*p == '@') {
879 strncpy(c->format_str, p + 1, 4); 1264 strncpy(pipe->format_str, p + 1, 4);
880 c->format_str[4] = '\0'; 1265 pipe->format_str[4] = '\0';
881 } 1266 }
882 1267
883 c->fourcc = format_fourcc(c->format_str); 1268 pipe->fourcc = format_fourcc(pipe->format_str);
884 if (c->fourcc == 0) { 1269 if (pipe->fourcc == 0) {
885 fprintf(stderr, "unknown format %s\n", c->format_str); 1270 fprintf(stderr, "unknown format %s\n", pipe->format_str);
886 return -1; 1271 return -1;
887 } 1272 }
888 1273
889 return 0; 1274 return 0;
890} 1275}
891 1276
892static int parse_plane(struct plane *p, const char *arg) 1277static int parse_plane(struct plane_arg *plane, const char *p)
893{ 1278{
894 strcpy(p->format_str, "XR24"); 1279 char *end;
895 1280
896 if (sscanf(arg, "%d:%dx%d@%4s", &p->con_id, &p->w, &p->h, &p->format_str) != 4 && 1281 memset(plane, 0, sizeof *plane);
897 sscanf(arg, "%d:%dx%d", &p->con_id, &p->w, &p->h) != 3)
898 return -1;
899 1282
900 p->fourcc = format_fourcc(p->format_str); 1283 plane->crtc_id = strtoul(p, &end, 10);
901 if (p->fourcc == 0) { 1284 if (*end != ':')
902 fprintf(stderr, "unknown format %s\n", p->format_str); 1285 return -EINVAL;
903 return -1; 1286
1287 p = end + 1;
1288 plane->w = strtoul(p, &end, 10);
1289 if (*end != 'x')
1290 return -EINVAL;
1291
1292 p = end + 1;
1293 plane->h = strtoul(p, &end, 10);
1294
1295 if (*end == '+' || *end == '-') {
1296 plane->x = strtol(end, &end, 10);
1297 if (*end != '+' && *end != '-')
1298 return -EINVAL;
1299 plane->y = strtol(end, &end, 10);
1300
1301 plane->has_position = true;
1302 }
1303
1304 if (*end == '*') {
1305 p = end + 1;
1306 plane->scale = strtod(p, &end);
1307 if (plane->scale <= 0.0)
1308 return -EINVAL;
1309 } else {
1310 plane->scale = 1.0;
1311 }
1312
1313 if (*end == '@') {
1314 p = end + 1;
1315 if (strlen(p) != 4)
1316 return -EINVAL;
1317
1318 strcpy(plane->format_str, p);
1319 } else {
1320 strcpy(plane->format_str, "XR24");
1321 }
1322
1323 plane->fourcc = format_fourcc(plane->format_str);
1324 if (plane->fourcc == 0) {
1325 fprintf(stderr, "unknown format %s\n", plane->format_str);
1326 return -EINVAL;
904 } 1327 }
905 1328
906 return 0; 1329 return 0;
907} 1330}
908 1331
909void usage(char *name) 1332static int parse_property(struct property_arg *p, const char *arg)
910{ 1333{
911 fprintf(stderr, "usage: %s [-ecpmf]\n", name); 1334 if (sscanf(arg, "%d:%32[^:]:%" SCNu64, &p->obj_id, p->name, &p->value) != 3)
912 fprintf(stderr, "\t-e\tlist encoders\n"); 1335 return -1;
1336
1337 p->obj_type = 0;
1338 p->name[DRM_PROP_NAME_LEN] = '\0';
1339
1340 return 0;
1341}
1342
1343static void usage(char *name)
1344{
1345 fprintf(stderr, "usage: %s [-cDdefMPpsvw]\n", name);
1346
1347 fprintf(stderr, "\n Query options:\n\n");
913 fprintf(stderr, "\t-c\tlist connectors\n"); 1348 fprintf(stderr, "\t-c\tlist connectors\n");
914 fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n"); 1349 fprintf(stderr, "\t-e\tlist encoders\n");
915 fprintf(stderr, "\t-m\tlist modes\n");
916 fprintf(stderr, "\t-f\tlist framebuffers\n"); 1350 fprintf(stderr, "\t-f\tlist framebuffers\n");
1351 fprintf(stderr, "\t-p\tlist CRTCs and planes (pipes)\n");
1352
1353 fprintf(stderr, "\n Test options:\n\n");
1354 fprintf(stderr, "\t-P <crtc_id>:<w>x<h>[+<x>+<y>][*<scale>][@<format>]\tset a plane\n");
1355 fprintf(stderr, "\t-s <connector_id>[,<connector_id>][@<crtc_id>]:<mode>[-<vrefresh>][@<format>]\tset a mode\n");
917 fprintf(stderr, "\t-v\ttest vsynced page flipping\n"); 1356 fprintf(stderr, "\t-v\ttest vsynced page flipping\n");
918 fprintf(stderr, "\t-s <connector_id>[@<crtc_id>]:<mode>[@<format>]\tset a mode\n"); 1357 fprintf(stderr, "\t-w <obj_id>:<prop_name>:<value>\tset property\n");
919 fprintf(stderr, "\t-P <connector_id>:<w>x<h>[@<format>]\tset a plane\n"); 1358
1359 fprintf(stderr, "\n Generic options:\n\n");
1360 fprintf(stderr, "\t-d\tdrop master after mode set\n");
1361 fprintf(stderr, "\t-M module\tuse the given driver\n");
1362 fprintf(stderr, "\t-D device\tuse the given device\n");
1363
920 fprintf(stderr, "\n\tDefault is to dump all info.\n"); 1364 fprintf(stderr, "\n\tDefault is to dump all info.\n");
921 exit(0); 1365 exit(0);
922} 1366}
923 1367
924#define dump_resource(res) if (res) dump_##res()
925
926static int page_flipping_supported(void) 1368static int page_flipping_supported(void)
927{ 1369{
928 /*FIXME: generic ioctl needed? */ 1370 /*FIXME: generic ioctl needed? */
@@ -944,48 +1386,101 @@ static int page_flipping_supported(void)
944#endif 1386#endif
945} 1387}
946 1388
1389static char optstr[] = "cdD:efM:P:ps:vw:";
1390
947int main(int argc, char **argv) 1391int main(int argc, char **argv)
948{ 1392{
1393 struct device dev;
1394
949 int c; 1395 int c;
950 int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0; 1396 int encoders = 0, connectors = 0, crtcs = 0, planes = 0, framebuffers = 0;
1397 int drop_master = 0;
951 int test_vsync = 0; 1398 int test_vsync = 0;
952 char *modules[] = { /* "i915", "radeon", "nouveau", "vmwgfx", */ "omapdrm" /*, "exynos" */}; 1399 const char *modules[] = { /* "i915", "radeon", "nouveau", "vmwgfx", */ "omapdrm" /*, "exynos" */};
1400 char *device = NULL;
1401 char *module = NULL;
953 unsigned int i; 1402 unsigned int i;
954 int count = 0, plane_count = 0; 1403 int count = 0, plane_count = 0;
955 struct connector con_args[2]; 1404 unsigned int prop_count = 0;
956 struct plane plane_args[2] = {0}; 1405 struct pipe_arg *pipe_args = NULL;
957 1406 struct plane_arg *plane_args = NULL;
1407 struct property_arg *prop_args = NULL;
1408 unsigned int args = 0;
1409 int ret;
1410
1411 memset(&dev, 0, sizeof dev);
1412
958 opterr = 0; 1413 opterr = 0;
959 while ((c = getopt(argc, argv, optstr)) != -1) { 1414 while ((c = getopt(argc, argv, optstr)) != -1) {
1415 args++;
1416
960 switch (c) { 1417 switch (c) {
961 case 'e':
962 encoders = 1;
963 break;
964 case 'c': 1418 case 'c':
965 connectors = 1; 1419 connectors = 1;
966 break; 1420 break;
967 case 'p': 1421 case 'D':
968 crtcs = 1; 1422 device = optarg;
969 planes = 1; 1423 args--;
970 break; 1424 break;
971 case 'm': 1425 case 'd':
972 modes = 1; 1426 drop_master = 1;
1427 break;
1428 case 'e':
1429 encoders = 1;
973 break; 1430 break;
974 case 'f': 1431 case 'f':
975 framebuffers = 1; 1432 framebuffers = 1;
976 break; 1433 break;
977 case 'v': 1434 case 'M':
978 test_vsync = 1; 1435 module = optarg;
1436 /* Preserve the default behaviour of dumping all information. */
1437 args--;
1438 break;
1439 case 'P':
1440 plane_args = realloc(plane_args,
1441 (plane_count + 1) * sizeof *plane_args);
1442 if (plane_args == NULL) {
1443 fprintf(stderr, "memory allocation failed\n");
1444 return 1;
1445 }
1446
1447 if (parse_plane(&plane_args[plane_count], optarg) < 0)
1448 usage(argv[0]);
1449
1450 plane_count++;
1451 break;
1452 case 'p':
1453 crtcs = 1;
1454 planes = 1;
979 break; 1455 break;
980 case 's': 1456 case 's':
981 if (parse_connector(&con_args[count], optarg) < 0) 1457 pipe_args = realloc(pipe_args,
1458 (count + 1) * sizeof *pipe_args);
1459 if (pipe_args == NULL) {
1460 fprintf(stderr, "memory allocation failed\n");
1461 return 1;
1462 }
1463
1464 if (parse_connector(&pipe_args[count], optarg) < 0)
982 usage(argv[0]); 1465 usage(argv[0]);
1466
983 count++; 1467 count++;
984 break; 1468 break;
985 case 'P': 1469 case 'v':
986 if (parse_plane(&plane_args[plane_count], optarg) < 0) 1470 test_vsync = 1;
1471 break;
1472 case 'w':
1473 prop_args = realloc(prop_args,
1474 (prop_count + 1) * sizeof *prop_args);
1475 if (prop_args == NULL) {
1476 fprintf(stderr, "memory allocation failed\n");
1477 return 1;
1478 }
1479
1480 if (parse_property(&prop_args[prop_count], optarg) < 0)
987 usage(argv[0]); 1481 usage(argv[0]);
988 plane_count++; 1482
1483 prop_count++;
989 break; 1484 break;
990 default: 1485 default:
991 usage(argv[0]); 1486 usage(argv[0]);
@@ -993,17 +1488,30 @@ int main(int argc, char **argv)
993 } 1488 }
994 } 1489 }
995 1490
996 if (argc == 1) 1491 if (!args)
997 encoders = connectors = crtcs = planes = modes = framebuffers = 1; 1492 encoders = connectors = crtcs = planes = framebuffers = 1;
998 1493
999 for (i = 0; i < ARRAY_SIZE(modules); i++) { 1494 if (module) {
1000 printf("trying to load module %s...", modules[i]); 1495 dev.fd = drmOpen(module, device);
1001 fd = drmOpen(modules[i], NULL); 1496 if (dev.fd < 0) {
1002 if (fd < 0) { 1497 fprintf(stderr, "failed to open device '%s'.\n", module);
1003 printf("failed.\n"); 1498 return 1;
1004 } else { 1499 }
1005 printf("success.\n"); 1500 } else {
1006 break; 1501 for (i = 0; i < ARRAY_SIZE(modules); i++) {
1502 printf("trying to open device '%s'...", modules[i]);
1503 dev.fd = drmOpen(modules[i], device);
1504 if (dev.fd < 0) {
1505 printf("failed.\n");
1506 } else {
1507 printf("success.\n");
1508 break;
1509 }
1510 }
1511
1512 if (dev.fd < 0) {
1513 fprintf(stderr, "no device found.\n");
1514 return 1;
1007 } 1515 }
1008 } 1516 }
1009 1517
@@ -1012,31 +1520,55 @@ int main(int argc, char **argv)
1012 return -1; 1520 return -1;
1013 } 1521 }
1014 1522
1015 if (i == ARRAY_SIZE(modules)) { 1523 if (test_vsync && !count) {
1016 fprintf(stderr, "failed to load any modules, aborting.\n"); 1524 fprintf(stderr, "page flipping requires at least one -s option.\n");
1017 return -1; 1525 return -1;
1018 } 1526 }
1019 1527
1020 resources = drmModeGetResources(fd); 1528 dev.resources = get_resources(&dev);
1021 if (!resources) { 1529 if (!dev.resources) {
1022 fprintf(stderr, "drmModeGetResources failed: %s\n", 1530 drmClose(dev.fd);
1023 strerror(errno));
1024 drmClose(fd);
1025 return 1; 1531 return 1;
1026 } 1532 }
1027 1533
1028 dump_resource(encoders); 1534#define dump_resource(dev, res) if (res) dump_##res(dev)
1029 dump_resource(connectors); 1535
1030 dump_resource(crtcs); 1536 dump_resource(&dev, encoders);
1031 dump_resource(planes); 1537 dump_resource(&dev, connectors);
1032 dump_resource(framebuffers); 1538 dump_resource(&dev, crtcs);
1539 dump_resource(&dev, planes);
1540 dump_resource(&dev, framebuffers);
1541
1542 for (i = 0; i < prop_count; ++i)
1543 set_property(&dev, &prop_args[i]);
1544
1545 if (count || plane_count) {
1546 ret = kms_create(dev.fd, &dev.kms);
1547 if (ret) {
1548 fprintf(stderr, "failed to create kms driver: %s\n",
1549 strerror(-ret));
1550 return 1;
1551 }
1552
1553 if (count)
1554 set_mode(&dev, pipe_args, count);
1555
1556 if (plane_count)
1557 set_planes(&dev, plane_args, plane_count);
1558
1559 if (test_vsync)
1560 test_page_flip(&dev, pipe_args, count);
1561
1562 if (drop_master)
1563 drmDropMaster(dev.fd);
1564
1565 kms_bo_destroy(&dev.mode.bo);
1566 kms_destroy(&dev.kms);
1033 1567
1034 if (count > 0) {
1035 set_mode(con_args, count, plane_args, plane_count, test_vsync);
1036 getchar(); 1568 getchar();
1037 } 1569 }
1038 1570
1039 drmModeFreeResources(resources); 1571 free_resources(dev.resources);
1040 1572
1041 return 0; 1573 return 0;
1042} 1574}