• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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