xref: /aosp_15_r20/external/libkmsxx/kms++util/src/testpat.cpp (revision f0687c8a10b3e371dbe09214db6664e37c283cca)
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