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 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 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 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 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