You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

conv.cxx 9.3KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365
  1. /* Copyright 2013-2014 Pierre Ossman <ossman@cendio.se> for Cendio AB
  2. *
  3. * This is free software; you can redistribute it and/or modify
  4. * it under the terms of the GNU General Public License as published by
  5. * the Free Software Foundation; either version 2 of the License, or
  6. * (at your option) any later version.
  7. *
  8. * This software is distributed in the hope that it will be useful,
  9. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  11. * GNU General Public License for more details.
  12. *
  13. * You should have received a copy of the GNU General Public License
  14. * along with this software; if not, write to the Free Software
  15. * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307,
  16. * USA.
  17. */
  18. #ifdef HAVE_CONFIG_H
  19. #include <config.h>
  20. #endif
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #include <rfb/PixelFormat.h>
  25. static const rdr::U8 pixelRed = 0xf1;
  26. static const rdr::U8 pixelGreen = 0xc3;
  27. static const rdr::U8 pixelBlue = 0x97;
  28. static const int fbWidth = 40;
  29. static const int fbHeight = 30;
  30. static const int fbArea = fbWidth * fbHeight;
  31. // Maximum bpp, plus some room for unaligned fudging
  32. static const int fbMalloc = (fbArea * 4) + 4;
  33. typedef bool (*testfn) (const rfb::PixelFormat&, const rfb::PixelFormat&);
  34. struct TestEntry {
  35. const char *label;
  36. testfn fn;
  37. };
  38. #define min(a,b) (((a) < (b)) ? (a) : (b))
  39. namespace rfb {
  40. void makePixel(const rfb::PixelFormat &pf,
  41. rdr::U8 *buffer)
  42. {
  43. rfb::Pixel p;
  44. p = 0;
  45. p |= (pixelRed >> (8 - pf.redBits)) << pf.redShift;
  46. p |= (pixelGreen >> (8 - pf.greenBits)) << pf.greenShift;
  47. p |= (pixelBlue >> (8 - pf.blueBits)) << pf.blueShift;
  48. // FIXME: Should we reimplement this as well?
  49. pf.bufferFromPixel(buffer, p);
  50. }
  51. bool verifyPixel(const rfb::PixelFormat &dstpf,
  52. const rfb::PixelFormat &srcpf,
  53. const rdr::U8 *buffer)
  54. {
  55. rfb::Pixel p;
  56. int r, g, b;
  57. int re, ge, be;
  58. // FIXME: Should we reimplement this as well?
  59. p = dstpf.pixelFromBuffer(buffer);
  60. r = (p >> dstpf.redShift) & dstpf.redMax;
  61. g = (p >> dstpf.greenShift) & dstpf.greenMax;
  62. b = (p >> dstpf.blueShift) & dstpf.blueMax;
  63. r = (r * 255 + dstpf.redMax/2) / dstpf.redMax;
  64. g = (g * 255 + dstpf.greenMax/2) / dstpf.greenMax;
  65. b = (b * 255 + dstpf.blueMax/2) / dstpf.blueMax;
  66. // The allowed error depends on:
  67. //
  68. // a) The number of bits the format can hold
  69. // b) The number of bits the source format could hold
  70. re = (1 << (8 - min(dstpf.redBits, srcpf.redBits))) - 1;
  71. ge = (1 << (8 - min(dstpf.greenBits, srcpf.greenBits))) - 1;
  72. be = (1 << (8 - min(dstpf.blueBits, srcpf.blueBits))) - 1;
  73. if (abs(r - pixelRed) > re)
  74. return false;
  75. if (abs(g - pixelGreen) > ge)
  76. return false;
  77. if (abs(b - pixelBlue) > be)
  78. return false;
  79. return true;
  80. }
  81. }
  82. using rfb::makePixel;
  83. using rfb::verifyPixel;
  84. static bool testPixel(const rfb::PixelFormat &dstpf,
  85. const rfb::PixelFormat &srcpf)
  86. {
  87. rfb::Pixel p;
  88. rdr::U8 buffer[4];
  89. makePixel(srcpf, buffer);
  90. p = srcpf.pixelFromBuffer(buffer);
  91. p = dstpf.pixelFromPixel(srcpf, p);
  92. memset(buffer, 0, sizeof(buffer));
  93. dstpf.bufferFromPixel(buffer, p);
  94. if (!verifyPixel(dstpf, srcpf, buffer))
  95. return false;
  96. return true;
  97. }
  98. static bool testBuffer(const rfb::PixelFormat &dstpf,
  99. const rfb::PixelFormat &srcpf)
  100. {
  101. int i, x, y, unaligned;
  102. rdr::U8 bufIn[fbMalloc], bufOut[fbMalloc];
  103. // Once aligned, and once unaligned
  104. for (unaligned = 0;unaligned < 2;unaligned++) {
  105. for (i = 0;i < fbArea;i++)
  106. makePixel(srcpf, bufIn + unaligned + i*srcpf.bpp/8);
  107. memset(bufOut, 0, sizeof(bufOut));
  108. dstpf.bufferFromBuffer(bufOut + unaligned, srcpf,
  109. bufIn + unaligned, fbArea);
  110. for (i = 0;i < fbArea;i++) {
  111. if (!verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8))
  112. return false;
  113. }
  114. memset(bufIn, 0, sizeof(bufIn));
  115. for (y = 0;y < fbHeight;y++) {
  116. for (x = 0;x < fbWidth/2;x++)
  117. makePixel(srcpf, bufIn + unaligned + (x + y*fbWidth)*srcpf.bpp/8);
  118. }
  119. memset(bufOut, 0, sizeof(bufOut));
  120. dstpf.bufferFromBuffer(bufOut + unaligned, srcpf, bufIn + unaligned,
  121. fbWidth/2, fbHeight, fbWidth, fbWidth);
  122. for (y = 0;y < fbHeight;y++) {
  123. for (x = 0;x < fbWidth;x++) {
  124. if (x < fbWidth/2) {
  125. if (!verifyPixel(dstpf, srcpf,
  126. bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8))
  127. return false;
  128. } else {
  129. const rdr::U8 zero[4] = { 0, 0, 0, 0 };
  130. if (memcmp(bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8, zero,
  131. dstpf.bpp/8) != 0)
  132. return false;
  133. }
  134. }
  135. }
  136. }
  137. return true;
  138. }
  139. static bool testRGB(const rfb::PixelFormat &dstpf,
  140. const rfb::PixelFormat &srcpf)
  141. {
  142. int i, x, y, unaligned;
  143. rdr::U8 bufIn[fbMalloc], bufRGB[fbMalloc], bufOut[fbMalloc];
  144. // Once aligned, and once unaligned
  145. for (unaligned = 0;unaligned < 2;unaligned++) {
  146. for (i = 0;i < fbArea;i++)
  147. makePixel(srcpf, bufIn + unaligned + i*srcpf.bpp/8);
  148. memset(bufRGB, 0, sizeof(bufRGB));
  149. srcpf.rgbFromBuffer(bufRGB + unaligned, bufIn + unaligned, fbArea);
  150. memset(bufOut, 0, sizeof(bufOut));
  151. dstpf.bufferFromRGB(bufOut + unaligned, bufRGB + unaligned, fbArea);
  152. for (i = 0;i < fbArea;i++) {
  153. if (!verifyPixel(dstpf, srcpf, bufOut + unaligned + i*dstpf.bpp/8))
  154. return false;
  155. }
  156. memset(bufIn, 0, sizeof(bufIn));
  157. for (y = 0;y < fbHeight;y++) {
  158. for (x = 0;x < fbWidth/2;x++)
  159. makePixel(srcpf, bufIn + unaligned + (x + y*fbWidth)*srcpf.bpp/8);
  160. }
  161. memset(bufRGB, 0, sizeof(bufRGB));
  162. srcpf.rgbFromBuffer(bufRGB + unaligned, bufIn + unaligned,
  163. fbWidth/2, fbWidth, fbHeight);
  164. memset(bufOut, 0, sizeof(bufOut));
  165. dstpf.bufferFromRGB(bufOut + unaligned, bufRGB + unaligned,
  166. fbWidth/2, fbWidth, fbHeight);
  167. for (y = 0;y < fbHeight;y++) {
  168. for (x = 0;x < fbWidth;x++) {
  169. if (x < fbWidth/2) {
  170. if (!verifyPixel(dstpf, srcpf,
  171. bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8))
  172. return false;
  173. } else {
  174. const rdr::U8 zero[4] = { 0, 0, 0, 0 };
  175. if (memcmp(bufOut + unaligned + (x + y*fbWidth)*dstpf.bpp/8, zero,
  176. dstpf.bpp/8) != 0)
  177. return false;
  178. }
  179. }
  180. }
  181. }
  182. return true;
  183. }
  184. static bool testPixelRGB(const rfb::PixelFormat &dstpf,
  185. const rfb::PixelFormat &srcpf)
  186. {
  187. rfb::Pixel p;
  188. rdr::U16 r16, g16, b16;
  189. rdr::U8 r8, g8, b8;
  190. rdr::U8 buffer[4];
  191. makePixel(srcpf, buffer);
  192. p = srcpf.pixelFromBuffer(buffer);
  193. srcpf.rgbFromPixel(p, &r16, &g16, &b16);
  194. p = dstpf.pixelFromRGB(r16, g16, b16);
  195. memset(buffer, 0, sizeof(buffer));
  196. dstpf.bufferFromPixel(buffer, p);
  197. if (!verifyPixel(dstpf, srcpf, buffer))
  198. return false;
  199. makePixel(srcpf, buffer);
  200. p = srcpf.pixelFromBuffer(buffer);
  201. srcpf.rgbFromPixel(p, &r8, &g8, &b8);
  202. p = dstpf.pixelFromRGB(r8, g8, b8);
  203. memset(buffer, 0, sizeof(buffer));
  204. dstpf.bufferFromPixel(buffer, p);
  205. if (!verifyPixel(dstpf, srcpf, buffer))
  206. return false;
  207. return true;
  208. }
  209. struct TestEntry tests[] = {
  210. {"Pixel from pixel", testPixel},
  211. {"Buffer from buffer", testBuffer},
  212. {"Buffer to/from RGB", testRGB},
  213. {"Pixel to/from RGB", testPixelRGB},
  214. };
  215. static void doTests(const rfb::PixelFormat &dstpf,
  216. const rfb::PixelFormat &srcpf)
  217. {
  218. size_t i;
  219. char dstb[256], srcb[256];
  220. dstpf.print(dstb, sizeof(dstb));
  221. srcpf.print(srcb, sizeof(srcb));
  222. printf("\n");
  223. printf("%s to %s\n", srcb, dstb);
  224. printf("\n");
  225. for (i = 0;i < sizeof(tests)/sizeof(tests[0]);i++) {
  226. printf(" %s: ", tests[i].label);
  227. fflush(stdout);
  228. if (tests[i].fn(dstpf, srcpf))
  229. printf("OK");
  230. else
  231. printf("FAILED");
  232. printf("\n");
  233. }
  234. }
  235. int main(int /*argc*/, char** /*argv*/)
  236. {
  237. rfb::PixelFormat dstpf, srcpf;
  238. printf("Pixel Conversion Correctness Test\n");
  239. /* rgb888 targets */
  240. dstpf.parse("rgb888");
  241. srcpf.parse("rgb888");
  242. doTests(dstpf, srcpf);
  243. srcpf.parse("bgr888");
  244. doTests(dstpf, srcpf);
  245. srcpf.parse("rgb565");
  246. doTests(dstpf, srcpf);
  247. srcpf.parse("rgb232");
  248. doTests(dstpf, srcpf);
  249. /* rgb565 targets */
  250. dstpf.parse("rgb565");
  251. srcpf.parse("rgb888");
  252. doTests(dstpf, srcpf);
  253. srcpf.parse("bgr565");
  254. doTests(dstpf, srcpf);
  255. srcpf.parse("rgb232");
  256. doTests(dstpf, srcpf);
  257. /* rgb232 targets */
  258. dstpf.parse("rgb232");
  259. srcpf.parse("rgb888");
  260. doTests(dstpf, srcpf);
  261. srcpf.parse("rgb565");
  262. doTests(dstpf, srcpf);
  263. srcpf.parse("bgr232");
  264. doTests(dstpf, srcpf);
  265. /* endian conversion (both ways) */
  266. dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
  267. srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 8, 16);
  268. doTests(dstpf, srcpf);
  269. doTests(srcpf, dstpf);
  270. dstpf = rfb::PixelFormat(16, 16, false, true, 31, 63, 31, 0, 5, 11);
  271. srcpf = rfb::PixelFormat(16, 16, true, true, 31, 63, 31, 0, 5, 11);
  272. doTests(dstpf, srcpf);
  273. doTests(srcpf, dstpf);
  274. // Pesky case that is very asymetrical
  275. dstpf = rfb::PixelFormat(32, 24, false, true, 255, 255, 255, 0, 8, 16);
  276. srcpf = rfb::PixelFormat(32, 24, true, true, 255, 255, 255, 0, 24, 8);
  277. doTests(dstpf, srcpf);
  278. doTests(srcpf, dstpf);
  279. }