2 #include <chrono>
3 #include <cstring>
4 #include <cassert>
6 #include <xf86drm.h>
7 #include <xf86drmMode.h>
8 #include <drm_fourcc.h>
9 #include <drm.h>
10 #include <drm_mode.h>
12 #include "kms++.h"
13 #include "color.h"
15 #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
17 namespace kms
18 {
19 static void draw_pixel(DumbFramebuffer& buf, unsigned x, unsigned y, RGB color)
20 {
21 static RGB c1;
23 switch (buf.format()) {
24 case PixelFormat::XRGB8888:
25 {
26 uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
27 *p = color.rgb888();
28 break;
29 }
30 case PixelFormat::XBGR8888:
31 {
32 uint32_t *p = (uint32_t*)(buf.map(0) + buf.stride(0) * y + x * 4);
33 *p = color.bgr888();
34 break;
35 }
36 case PixelFormat::RGB565:
37 {
38 uint16_t *p = (uint16_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
39 *p = color.rgb565();
40 break;
41 }
42 case PixelFormat::UYVY:
43 case PixelFormat::YUYV:
44 case PixelFormat::YVYU:
45 case PixelFormat::VYUY:
46 {
47 if ((x & 1) == 0) {
48 c1 = color;
49 return;
50 }
52 uint8_t *p = (uint8_t*)(buf.map(0) + buf.stride(0) * y + x * 2);
54 YUV yuv1 = c1.yuv();
55 YUV yuv2 = color.yuv();
57 switch (buf.format()) {
58 case PixelFormat::UYVY:
59 p[0] = (yuv1.u + yuv2.u) / 2;
60 p[1] = yuv1.y;
61 p[2] = (yuv1.v + yuv2.v) / 2;
62 p[3] = yuv2.y;
63 break;
65 case PixelFormat::YUYV:
66 p[0] = yuv1.y;
67 p[1] = (yuv1.u + yuv2.u) / 2;
68 p[2] = yuv2.y;
69 p[3] = (yuv1.v + yuv2.v) / 2;
70 break;
72 case PixelFormat::YVYU:
73 p[0] = yuv1.y;
74 p[1] = (yuv1.v + yuv2.v) / 2;
75 p[2] = yuv2.y;
76 p[3] = (yuv1.u + yuv2.u) / 2;
77 break;
79 case PixelFormat::VYUY:
80 p[0] = (yuv1.v + yuv2.v) / 2;
81 p[1] = yuv1.y;
82 p[2] = (yuv1.u + yuv2.u) / 2;
83 p[3] = yuv2.y;
84 break;
85 default:
86 break;
87 }
89 break;
90 }
91 default:
92 throw std::invalid_argument("unknown pixelformat");
93 }
94 }
96 static void draw_rgb_test_pattern(DumbFramebuffer& fb)
97 {
98 unsigned x, y;
99 unsigned w = fb.width();
100 unsigned h = fb.height();
102 const unsigned mw = 20;
104 const unsigned xm1 = mw;
105 const unsigned xm2 = w - mw - 1;
106 const unsigned ym1 = mw;
107 const unsigned ym2 = h - mw - 1;
109 for (y = 0; y < h; y++) {
110 for (x = 0; x < w; x++) {
111 // white margin lines
112 if (x == xm1 || x == xm2 || y == ym1 || y == ym2)
113 draw_pixel(fb, x, y, RGB(255, 255, 255));
114 // white box outlines to corners
115 else if ((x == 0 || x == w - 1) && (y < ym1 || y > ym2))
116 draw_pixel(fb, x, y, RGB(255, 255, 255));
117 // white box outlines to corners
118 else if ((y == 0 || y == h - 1) && (x < xm1 || x > xm2))
119 draw_pixel(fb, x, y, RGB(255, 255, 255));
120 // blue bar on the left
121 else if (x < xm1 && (y > ym1 && y < ym2))
122 draw_pixel(fb, x, y, RGB(0, 0, 255));
123 // blue bar on the top
124 else if (y < ym1 && (x > xm1 && x < xm2))
125 draw_pixel(fb, x, y, RGB(0, 0, 255));
126 // red bar on the right
127 else if (x > xm2 && (y > ym1 && y < ym2))
128 draw_pixel(fb, x, y, RGB(255, 0, 0));
129 // red bar on the bottom
130 else if (y > ym2 && (x > xm1 && x < xm2))
131 draw_pixel(fb, x, y, RGB(255, 0, 0));
132 // inside the margins
133 else if (x > xm1 && x < xm2 && y > ym1 && y < ym2) {
134 // diagonal line
135 if (x == y || w - x == h - y)
136 draw_pixel(fb, x, y, RGB(255, 255, 255));
137 // diagonal line
138 else if (w - x == y || x == h - y)
139 draw_pixel(fb, x, y, RGB(255, 255, 255));
140 else {
141 int t = (x - xm1 - 1) * 3 / (xm2 - xm1 - 1);
142 unsigned r = 0, g = 0, b = 0;
144 unsigned c = (y - ym1 - 1) % 256;
146 switch (t) {
147 case 0:
148 r = c;
149 break;
150 case 1:
151 g = c;
152 break;
153 case 2:
154 b = c;
155 break;
156 }
158 draw_pixel(fb, x, y, RGB(r, g, b));
159 }
160 // black corners
161 } else {
162 draw_pixel(fb, x, y, RGB(0, 0, 0));
163 }
164 }
165 }
166 }
168 void draw_test_pattern(DumbFramebuffer& fb)
169 {
170 using namespace std::chrono;
172 auto t1 = high_resolution_clock::now();
174 draw_rgb_test_pattern(fb);
176 auto t2 = high_resolution_clock::now();
177 auto time_span = duration_cast<microseconds>(t2 - t1);
179 printf("draw took %u us\n", (unsigned)time_span.count());
180 }
181 }