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