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