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