2 //#define DRAW_PERF_PRINT
4 #include <cstring>
5 #include <cassert>
6 #include <thread>
8 #include <kms++/kms++.h>
9 #include <kms++util/kms++util.h>
11 using namespace std;
13 namespace kms
14 {
16 static RGB get_test_pattern_pixel(IMappedFramebuffer& fb, unsigned x, unsigned y)
17 {
18 const unsigned w = fb.width();
19 const unsigned h = fb.height();
21 const unsigned mw = 20;
23 const unsigned xm1 = mw;
24 const unsigned xm2 = w - mw - 1;
25 const unsigned ym1 = mw;
26 const unsigned ym2 = h - mw - 1;
28 // white margin lines
29 if (x == xm1 || x == xm2 || y == ym1 || y == ym2)
30 return RGB(255, 255, 255);
31 // white box outlines to corners
32 else if ((x == 0 || x == w - 1) && (y < ym1 || y > ym2))
33 return RGB(255, 255, 255);
34 // white box outlines to corners
35 else if ((y == 0 || y == h - 1) && (x < xm1 || x > xm2))
36 return RGB(255, 255, 255);
37 // blue bar on the left
38 else if (x < xm1 && (y > ym1 && y < ym2))
39 return RGB(0, 0, 255);
40 // blue bar on the top
41 else if (y < ym1 && (x > xm1 && x < xm2))
42 return RGB(0, 0, 255);
43 // red bar on the right
44 else if (x > xm2 && (y > ym1 && y < ym2))
45 return RGB(255, 0, 0);
46 // red bar on the bottom
47 else if (y > ym2 && (x > xm1 && x < xm2))
48 return RGB(255, 0, 0);
49 // inside the margins
50 else if (x > xm1 && x < xm2 && y > ym1 && y < ym2) {
51 // diagonal line
52 if (x == y || w - x == h - y)
53 return RGB(255, 255, 255);
54 // diagonal line
55 else if (w - x == y || x == h - y)
56 return RGB(255, 255, 255);
57 else {
58 int t = (x - xm1 - 1) * 8 / (xm2 - xm1 - 1);
59 unsigned r = 0, g = 0, b = 0;
61 unsigned c = (y - ym1 - 1) % 256;
63 switch (t) {
64 case 0:
65 r = c;
66 break;
67 case 1:
68 g = c;
69 break;
70 case 2:
71 b = c;
72 break;
73 case 3:
74 g = b = c;
75 break;
76 case 4:
77 r = b = c;
78 break;
79 case 5:
80 r = g = c;
81 break;
82 case 6:
83 r = g = b = c;
84 break;
85 case 7:
86 break;
87 }
89 return RGB(r, g, b);
90 }
91 } else {
92 // black corners
93 return RGB(0, 0, 0);
94 }
95 }
97 static void draw_test_pattern_part(IMappedFramebuffer& fb, unsigned start_y, unsigned end_y)
98 {
99 unsigned x, y;
100 unsigned w = fb.width();
102 switch (fb.format()) {
103 case PixelFormat::XRGB8888:
104 case PixelFormat::XBGR8888:
105 case PixelFormat::ARGB8888:
106 case PixelFormat::ABGR8888:
107 case PixelFormat::RGB565:
108 for (y = start_y; y < end_y; y++) {
109 for (x = 0; x < w; x++) {
110 RGB pixel = get_test_pattern_pixel(fb, x, y);
111 draw_rgb_pixel(fb, x, y, pixel);
112 }
113 }
114 break;
116 case PixelFormat::UYVY:
117 case PixelFormat::YUYV:
118 case PixelFormat::YVYU:
119 case PixelFormat::VYUY:
120 for (y = start_y; y < end_y; y++) {
121 for (x = 0; x < w; x += 2) {
122 RGB pixel1 = get_test_pattern_pixel(fb, x, y);
123 RGB pixel2 = get_test_pattern_pixel(fb, x + 1, y);
124 draw_yuv422_macropixel(fb, x, y, pixel1.yuv(), pixel2.yuv());
125 }
126 }
127 break;
129 case PixelFormat::NV12:
130 case PixelFormat::NV21:
131 for (y = start_y; y < end_y; y += 2) {
132 for (x = 0; x < w; x += 2) {
133 RGB pixel00 = get_test_pattern_pixel(fb, x, y);
134 RGB pixel10 = get_test_pattern_pixel(fb, x + 1, y);
135 RGB pixel01 = get_test_pattern_pixel(fb, x, y + 1);
136 RGB pixel11 = get_test_pattern_pixel(fb, x + 1, y + 1);
137 draw_yuv420_macropixel(fb, x, y,
138 pixel00.yuv(), pixel10.yuv(),
139 pixel01.yuv(), pixel11.yuv());
140 }
141 }
142 break;
143 default:
144 throw std::invalid_argument("unknown pixelformat");
145 }
146 }
148 static void draw_test_pattern_impl(IMappedFramebuffer& fb)
149 {
150 if (fb.height() < 20) {
151 draw_test_pattern_part(fb, 0, fb.height());
152 return;
153 }
155 unsigned num_threads = thread::hardware_concurrency();
156 vector<thread> workers;
158 unsigned part = (fb.height() / num_threads) & ~1;
160 for (unsigned n = 0; n < num_threads; ++n) {
161 unsigned start = n * part;
162 unsigned end = start + part;
164 if (n == num_threads - 1)
165 end = fb.height();
167 workers.push_back(thread([&fb, start, end]() { draw_test_pattern_part(fb, start, end); }));
168 }
170 for (thread& t : workers)
171 t.join();
172 }
174 void draw_test_pattern(IMappedFramebuffer &fb)
175 {
176 #ifdef DRAW_PERF_PRINT
177 Stopwatch sw;
178 sw.start();
179 #endif
181 draw_test_pattern_impl(fb);
183 #ifdef DRAW_PERF_PRINT
184 double us = sw.elapsed_us();
185 printf("draw took %u us\n", (unsigned)us);
186 #endif
187 }
189 }