1
2 //#define DRAW_PERF_PRINT
3
4 #include <cstring>
5 #include <cassert>
6
7 #ifdef HAS_PTHREAD
8 #include <thread>
9 #endif
10
11 #include <kms++/kms++.h>
12 #include <kms++util/kms++util.h>
13
14 using namespace std;
15
16 namespace kms
17 {
18
get_test_pattern_pixel(IFramebuffer & fb,unsigned x,unsigned y)19 static RGB get_test_pattern_pixel(IFramebuffer& fb, unsigned x, unsigned y)
20 {
21 const unsigned w = fb.width();
22 const unsigned h = fb.height();
23
24 const unsigned mw = 20;
25
26 const unsigned xm1 = mw;
27 const unsigned xm2 = w - mw - 1;
28 const unsigned ym1 = mw;
29 const unsigned ym2 = h - mw - 1;
30
31 // white margin lines
32 if (x == xm1 || x == xm2 || y == ym1 || y == ym2)
33 return RGB(255, 255, 255);
34 // white box in top left corner
35 else if (x < xm1 && y < ym1)
36 return RGB(255, 255, 255);
37 // white box outlines to corners
38 else if ((x == 0 || x == w - 1) && (y < ym1 || y > ym2))
39 return RGB(255, 255, 255);
40 // white box outlines to corners
41 else if ((y == 0 || y == h - 1) && (x < xm1 || x > xm2))
42 return RGB(255, 255, 255);
43 // blue bar on the left
44 else if (x < xm1 && (y > ym1 && y < ym2))
45 return RGB(0, 0, 255);
46 // blue bar on the top
47 else if (y < ym1 && (x > xm1 && x < xm2))
48 return RGB(0, 0, 255);
49 // red bar on the right
50 else if (x > xm2 && (y > ym1 && y < ym2))
51 return RGB(255, 0, 0);
52 // red bar on the bottom
53 else if (y > ym2 && (x > xm1 && x < xm2))
54 return RGB(255, 0, 0);
55 // inside the margins
56 else if (x > xm1 && x < xm2 && y > ym1 && y < ym2) {
57 // diagonal line
58 if (x == y || w - x == h - y)
59 return RGB(255, 255, 255);
60 // diagonal line
61 else if (w - x - 1 == y || x == h - y - 1)
62 return RGB(255, 255, 255);
63 else {
64 int t = (x - xm1 - 1) * 8 / (xm2 - xm1 - 1);
65 unsigned r = 0, g = 0, b = 0;
66
67 unsigned c = (y - ym1 - 1) % 256;
68
69 switch (t) {
70 case 0:
71 r = c;
72 break;
73 case 1:
74 g = c;
75 break;
76 case 2:
77 b = c;
78 break;
79 case 3:
80 g = b = c;
81 break;
82 case 4:
83 r = b = c;
84 break;
85 case 5:
86 r = g = c;
87 break;
88 case 6:
89 r = g = b = c;
90 break;
91 case 7:
92 break;
93 }
94
95 return RGB(r, g, b);
96 }
97 } else {
98 // black corners
99 return RGB(0, 0, 0);
100 }
101 }
102
draw_test_pattern_part(IFramebuffer & fb,unsigned start_y,unsigned end_y,YUVType yuvt)103 static void draw_test_pattern_part(IFramebuffer& fb, unsigned start_y, unsigned end_y, YUVType yuvt)
104 {
105 unsigned x, y;
106 unsigned w = fb.width();
107
108 const PixelFormatInfo& format_info = get_pixel_format_info(fb.format());
109
110 switch (format_info.type) {
111 case PixelColorType::RGB:
112 for (y = start_y; y < end_y; y++) {
113 for (x = 0; x < w; x++) {
114 RGB pixel = get_test_pattern_pixel(fb, x, y);
115 draw_rgb_pixel(fb, x, y, pixel);
116 }
117 }
118 break;
119
120 case PixelColorType::YUV:
121 switch (format_info.num_planes) {
122 case 1:
123 for (y = start_y; y < end_y; y++) {
124 for (x = 0; x < w; x += 2) {
125 RGB pixel1 = get_test_pattern_pixel(fb, x, y);
126 RGB pixel2 = get_test_pattern_pixel(fb, x + 1, y);
127 draw_yuv422_macropixel(fb, x, y, pixel1.yuv(yuvt), pixel2.yuv(yuvt));
128 }
129 }
130 break;
131
132 case 2:
133 for (y = start_y; y < end_y; y += 2) {
134 for (x = 0; x < w; x += 2) {
135 RGB pixel00 = get_test_pattern_pixel(fb, x, y);
136 RGB pixel10 = get_test_pattern_pixel(fb, x + 1, y);
137 RGB pixel01 = get_test_pattern_pixel(fb, x, y + 1);
138 RGB pixel11 = get_test_pattern_pixel(fb, x + 1, y + 1);
139 draw_yuv420_macropixel(fb, x, y,
140 pixel00.yuv(yuvt), pixel10.yuv(yuvt),
141 pixel01.yuv(yuvt), pixel11.yuv(yuvt));
142 }
143 }
144 break;
145
146 default:
147 throw invalid_argument("unsupported number of pixel format planes");
148 }
149
150 break;
151
152 default:
153 throw invalid_argument("unsupported pixel format");
154 }
155 }
156
draw_test_pattern_impl(IFramebuffer & fb,YUVType yuvt)157 static void draw_test_pattern_impl(IFramebuffer& fb, YUVType yuvt)
158 {
159 #ifdef HAS_PTHREAD
160 if (fb.height() < 20) {
161 draw_test_pattern_part(fb, 0, fb.height(), yuvt);
162 return;
163 }
164
165 // Create the mmaps before starting the threads
166 for (unsigned i = 0; i < fb.num_planes(); ++i)
167 fb.map(0);
168
169 unsigned num_threads = thread::hardware_concurrency();
170 vector<thread> workers;
171
172 unsigned part = (fb.height() / num_threads) & ~1;
173
174 for (unsigned n = 0; n < num_threads; ++n) {
175 unsigned start = n * part;
176 unsigned end = start + part;
177
178 if (n == num_threads - 1)
179 end = fb.height();
180
181 workers.push_back(thread([&fb, start, end, yuvt]() { draw_test_pattern_part(fb, start, end, yuvt); }));
182 }
183
184 for (thread& t : workers)
185 t.join();
186 #else
187 draw_test_pattern_part(fb, 0, fb.height(), yuvt);
188 #endif
189 }
190
draw_test_pattern(IFramebuffer & fb,YUVType yuvt)191 void draw_test_pattern(IFramebuffer &fb, YUVType yuvt)
192 {
193 #ifdef DRAW_PERF_PRINT
194 Stopwatch sw;
195 sw.start();
196 #endif
197
198 draw_test_pattern_impl(fb, yuvt);
199
200 #ifdef DRAW_PERF_PRINT
201 double us = sw.elapsed_us();
202 printf("draw took %u us\n", (unsigned)us);
203 #endif
204 }
205
206 }
207