threaded_testbed.c 21 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686
  1. //---------------------------------------------------------------------------------
  2. //
  3. // Little Color Management System, multithreaded extensions
  4. // Copyright (c) 1998-2022 Marti Maria Saguer, all rights reserved
  5. //
  6. // This program is free software: you can redistribute it and/or modify
  7. // it under the terms of the GNU General Public License as published by
  8. // the Free Software Foundation, either version 3 of the License, or
  9. // (at your option) any later version.
  10. //
  11. // This program is distributed in the hope that it will be useful,
  12. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. // GNU General Public License for more details.
  15. //
  16. // You should have received a copy of the GNU General Public License
  17. // along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. //
  19. //---------------------------------------------------------------------------------
  20. #include "threaded_internal.h"
  21. #include <stdlib.h>
  22. #include <memory.h>
  23. #include <time.h>
  24. // A fast way to convert from/to 16 <-> 8 bits
  25. #define FROM_8_TO_16(rgb) (cmsUInt16Number) ((((cmsUInt16Number) (rgb)) << 8)|(rgb))
  26. #define FROM_16_TO_8(rgb) (cmsUInt8Number) ((((rgb) * 65281 + 8388608) >> 24) & 0xFF)
  27. // Some pixel representations
  28. typedef struct { cmsUInt8Number r, g, b; } Scanline_rgb8bits;
  29. typedef struct { cmsUInt8Number r, g, b, a; } Scanline_rgba8bits;
  30. typedef struct { cmsUInt8Number c, m, y, k; } Scanline_cmyk8bits;
  31. typedef struct { cmsUInt16Number r, g, b; } Scanline_rgb16bits;
  32. typedef struct { cmsUInt16Number r, g, b, a; } Scanline_rgba16bits;
  33. typedef struct { cmsUInt16Number c, m, y, k; } Scanline_cmyk16bits;
  34. static struct timespec start, finish;
  35. cmsINLINE void MeasureTimeStart(void)
  36. {
  37. #ifdef CMS_IS_WINDOWS_
  38. timespec_get(&start, TIME_UTC);
  39. #else
  40. clock_gettime(CLOCK_MONOTONIC, &start);
  41. #endif
  42. }
  43. cmsINLINE double MeasureTimeStop(void)
  44. {
  45. double elapsed;
  46. #ifdef CMS_IS_WINDOWS_
  47. timespec_get(&finish, TIME_UTC);
  48. #else
  49. clock_gettime(CLOCK_MONOTONIC, &finish);
  50. #endif
  51. elapsed = ((double) finish.tv_sec - start.tv_sec);
  52. elapsed += ((double) finish.tv_nsec - start.tv_nsec) / 1000000000.0;
  53. return elapsed;
  54. }
  55. // A flushed printf
  56. static
  57. void trace(const char* frm, ...)
  58. {
  59. va_list args;
  60. va_start(args, frm);
  61. vfprintf(stderr, frm, args);
  62. fflush(stderr);
  63. va_end(args);
  64. }
  65. // The callback function used by cmsSetLogErrorHandler()
  66. static
  67. void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text)
  68. {
  69. UNUSED_PARAMETER(ContextID);
  70. UNUSED_PARAMETER(ErrorCode);
  71. trace("** Fatal error: %s\n", Text);
  72. exit(1);
  73. }
  74. // Rise an error and exit
  75. static
  76. void Fail(const char* frm, ...)
  77. {
  78. char ReasonToFailBuffer[1024];
  79. va_list args;
  80. va_start(args, frm);
  81. vsprintf(ReasonToFailBuffer, frm, args);
  82. FatalErrorQuit(0, 0, ReasonToFailBuffer);
  83. // unreachable va_end(args);
  84. }
  85. // Creates a fake profile that only has a curve. Used in several places
  86. static
  87. cmsHPROFILE CreateCurves(void)
  88. {
  89. cmsToneCurve* Gamma = cmsBuildGamma(0, 1.1);
  90. cmsToneCurve* Transfer[3];
  91. cmsHPROFILE h;
  92. Transfer[0] = Transfer[1] = Transfer[2] = Gamma;
  93. h = cmsCreateLinearizationDeviceLink(cmsSigRgbData, Transfer);
  94. cmsFreeToneCurve(Gamma);
  95. return h;
  96. }
  97. // --------------------------------------------------------------------------------------------------
  98. // A C C U R A C Y C H E C K S
  99. // --------------------------------------------------------------------------------------------------
  100. // Check change format feature
  101. static
  102. void CheckChangeFormat(void)
  103. {
  104. cmsHPROFILE hsRGB, hLab;
  105. cmsHTRANSFORM xform;
  106. cmsUInt8Number rgb8[3] = { 10, 120, 40 };
  107. cmsUInt16Number rgb16[3] = { 10* 257, 120*257, 40*257 };
  108. cmsUInt16Number lab16_1[3], lab16_2[3];
  109. trace("Checking change format feature...");
  110. hsRGB = cmsCreate_sRGBProfile();
  111. hLab = cmsCreateLab4Profile(NULL);
  112. xform = cmsCreateTransform(hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, 0);
  113. cmsCloseProfile(hsRGB);
  114. cmsCloseProfile(hLab);
  115. cmsDoTransform(xform, rgb16, lab16_1, 1);
  116. cmsChangeBuffersFormat(xform, TYPE_RGB_8, TYPE_Lab_16);
  117. cmsDoTransform(xform, rgb8, lab16_2, 1);
  118. cmsDeleteTransform(xform);
  119. if (memcmp(lab16_1, lab16_2, sizeof(lab16_1)) != 0)
  120. Fail("Change format failed!");
  121. trace("Ok\n");
  122. }
  123. // --------------------------------------------------------------------------------------------------
  124. // P E R F O R M A N C E C H E C K S
  125. // --------------------------------------------------------------------------------------------------
  126. static
  127. cmsFloat64Number MPixSec(cmsFloat64Number seconds)
  128. {
  129. return (256.0 * 256.0 * 256.0) / (1024.0*1024.0*seconds);
  130. }
  131. typedef cmsFloat64Number(*perf_fn)(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut);
  132. static
  133. void PerformanceHeader(void)
  134. {
  135. trace(" MPixel/sec. MByte/sec.\n");
  136. }
  137. static
  138. cmsHPROFILE loadProfile(const char* name)
  139. {
  140. if (*name == '*')
  141. {
  142. if (strcmp(name, "*lab") == 0)
  143. {
  144. return cmsCreateLab4Profile(NULL);
  145. }
  146. else
  147. if (strcmp(name, "*xyz") == 0)
  148. {
  149. return cmsCreateXYZProfile();
  150. }
  151. else
  152. if (strcmp(name, "*curves") == 0)
  153. {
  154. return CreateCurves();
  155. }
  156. else
  157. Fail("Unknown builtin '%s'", name);
  158. }
  159. return cmsOpenProfileFromFile(name, "r");
  160. }
  161. static
  162. cmsFloat64Number Performance(const char* Title, perf_fn fn, cmsContext ct, const char* inICC, const char* outICC, size_t sz, cmsFloat64Number prev)
  163. {
  164. cmsHPROFILE hlcmsProfileIn = loadProfile(inICC);
  165. cmsHPROFILE hlcmsProfileOut = loadProfile(outICC);
  166. cmsFloat64Number n = fn(ct, hlcmsProfileIn, hlcmsProfileOut);
  167. trace("%-30s: ", Title); fflush(stdout);
  168. trace("%-12.2f %-12.2f", n, n * sz);
  169. if (prev > 0.0) {
  170. cmsFloat64Number imp = n / prev;
  171. if (imp > 1)
  172. trace(" (x %-2.1f)", imp);
  173. }
  174. trace("\n"); fflush(stdout);
  175. return n;
  176. }
  177. static
  178. void ComparativeCt(cmsContext ct1, cmsContext ct2, const char* Title, perf_fn fn1, perf_fn fn2, const char* inICC, const char* outICC)
  179. {
  180. cmsHPROFILE hlcmsProfileIn;
  181. cmsHPROFILE hlcmsProfileOut;
  182. if (inICC == NULL)
  183. hlcmsProfileIn = CreateCurves();
  184. else
  185. hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r");
  186. if (outICC == NULL)
  187. hlcmsProfileOut = CreateCurves();
  188. else
  189. hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r");
  190. cmsFloat64Number n1 = fn1(ct1, hlcmsProfileIn, hlcmsProfileOut);
  191. if (inICC == NULL)
  192. hlcmsProfileIn = CreateCurves();
  193. else
  194. hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r");
  195. if (outICC == NULL)
  196. hlcmsProfileOut = CreateCurves();
  197. else
  198. hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r");
  199. cmsFloat64Number n2 = fn2(ct2, hlcmsProfileIn, hlcmsProfileOut);
  200. trace("%-30s: ", Title); fflush(stdout);
  201. trace("%-12.2f %-12.2f\n", n1, n2);
  202. }
  203. static
  204. void Comparative(const char* Title, perf_fn fn1, perf_fn fn2, const char* inICC, const char* outICC)
  205. {
  206. ComparativeCt(0, 0, Title, fn1, fn2, inICC, outICC);
  207. }
  208. // The worst case is used, no cache and all rgb combinations
  209. static
  210. cmsFloat64Number SpeedTest8bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  211. {
  212. cmsInt32Number r, g, b, j;
  213. cmsFloat64Number diff;
  214. cmsHTRANSFORM hlcmsxform;
  215. Scanline_rgb8bits *In;
  216. cmsUInt32Number Mb;
  217. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  218. Fail("Unable to open profiles");
  219. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  220. cmsCloseProfile(hlcmsProfileIn);
  221. cmsCloseProfile(hlcmsProfileOut);
  222. Mb = 256 * 256 * 256 * sizeof(Scanline_rgb8bits);
  223. In = (Scanline_rgb8bits*)malloc(Mb);
  224. j = 0;
  225. for (r = 0; r < 256; r++)
  226. for (g = 0; g < 256; g++)
  227. for (b = 0; b < 256; b++) {
  228. In[j].r = (cmsUInt8Number)r;
  229. In[j].g = (cmsUInt8Number)g;
  230. In[j].b = (cmsUInt8Number)b;
  231. j++;
  232. }
  233. MeasureTimeStart();
  234. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  235. diff = MeasureTimeStop();
  236. free(In);
  237. cmsDeleteTransform(hlcmsxform);
  238. return MPixSec(diff);
  239. }
  240. static
  241. cmsFloat64Number SpeedTest8bitsRGBA(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  242. {
  243. cmsInt32Number r, g, b, j;
  244. cmsFloat64Number diff;
  245. cmsHTRANSFORM hlcmsxform;
  246. Scanline_rgba8bits *In;
  247. cmsUInt32Number Mb;
  248. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  249. Fail("Unable to open profiles");
  250. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  251. cmsCloseProfile(hlcmsProfileIn);
  252. cmsCloseProfile(hlcmsProfileOut);
  253. Mb = 256 * 256 * 256 * sizeof(Scanline_rgba8bits);
  254. In = (Scanline_rgba8bits*)malloc(Mb);
  255. j = 0;
  256. for (r = 0; r < 256; r++)
  257. for (g = 0; g < 256; g++)
  258. for (b = 0; b < 256; b++) {
  259. In[j].r = (cmsUInt8Number)r;
  260. In[j].g = (cmsUInt8Number)g;
  261. In[j].b = (cmsUInt8Number)b;
  262. In[j].a = 0;
  263. j++;
  264. }
  265. MeasureTimeStart();
  266. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  267. diff = MeasureTimeStop();
  268. free(In);
  269. cmsDeleteTransform(hlcmsxform);
  270. return MPixSec(diff);
  271. }
  272. // The worst case is used, no cache and all rgb combinations
  273. static
  274. cmsFloat64Number SpeedTest16bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  275. {
  276. cmsInt32Number r, g, b, j;
  277. cmsFloat64Number diff;
  278. cmsHTRANSFORM hlcmsxform;
  279. Scanline_rgb16bits *In;
  280. cmsUInt32Number Mb;
  281. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  282. Fail("Unable to open profiles");
  283. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  284. cmsCloseProfile(hlcmsProfileIn);
  285. cmsCloseProfile(hlcmsProfileOut);
  286. Mb = 256 * 256 * 256 * sizeof(Scanline_rgb16bits);
  287. In = (Scanline_rgb16bits*)malloc(Mb);
  288. j = 0;
  289. for (r = 0; r < 256; r++)
  290. for (g = 0; g < 256; g++)
  291. for (b = 0; b < 256; b++) {
  292. In[j].r = (cmsUInt16Number)FROM_8_TO_16(r);
  293. In[j].g = (cmsUInt16Number)FROM_8_TO_16(g);
  294. In[j].b = (cmsUInt16Number)FROM_8_TO_16(b);
  295. j++;
  296. }
  297. MeasureTimeStart();
  298. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  299. diff = MeasureTimeStop();
  300. free(In);
  301. cmsDeleteTransform(hlcmsxform);
  302. return MPixSec(diff);
  303. }
  304. static
  305. cmsFloat64Number SpeedTest16bitsCMYK(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  306. {
  307. cmsInt32Number r, g, b, j;
  308. cmsFloat64Number diff;
  309. cmsHTRANSFORM hlcmsxform;
  310. Scanline_cmyk16bits* In;
  311. cmsUInt32Number Mb;
  312. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  313. Fail("Unable to open profiles");
  314. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_CMYK_16, hlcmsProfileOut, TYPE_CMYK_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  315. cmsCloseProfile(hlcmsProfileIn);
  316. cmsCloseProfile(hlcmsProfileOut);
  317. Mb = 256 * 256 * 256 * sizeof(Scanline_cmyk16bits);
  318. In = (Scanline_cmyk16bits*)malloc(Mb);
  319. j = 0;
  320. for (r = 0; r < 256; r++)
  321. for (g = 0; g < 256; g++)
  322. for (b = 0; b < 256; b++) {
  323. In[j].c = (cmsUInt16Number)r;
  324. In[j].m = (cmsUInt16Number)g;
  325. In[j].y = (cmsUInt16Number)b;
  326. In[j].k = (cmsUInt16Number)r;
  327. j++;
  328. }
  329. MeasureTimeStart();
  330. cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256);
  331. diff = MeasureTimeStop();
  332. free(In);
  333. cmsDeleteTransform(hlcmsxform);
  334. return MPixSec(diff);
  335. }
  336. static
  337. void SpeedTest8(void)
  338. {
  339. cmsContext noPlugin = cmsCreateContext(0, 0);
  340. cmsFloat64Number t[10];
  341. trace("\n\n");
  342. trace("P E R F O R M A N C E T E S T S 8 B I T S (D E F A U L T)\n");
  343. trace("==============================================================\n\n");
  344. fflush(stdout);
  345. PerformanceHeader();
  346. t[0] = Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), 0);
  347. t[1] = Performance("8 bits on Matrix-Shaper ", SpeedTest8bitsRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0);
  348. t[2] = Performance("8 bits on same MatrixSh ", SpeedTest8bitsRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0);
  349. t[3] = Performance("8 bits on curves ", SpeedTest8bitsRGB, noPlugin, "*curves", "*curves", sizeof(Scanline_rgb8bits), 0);
  350. // Note that context 0 has the plug-in installed
  351. trace("\n\n");
  352. trace("P E R F O R M A N C E T E S T S 8 B I T S (P L U G I N)\n");
  353. trace("===========================================================\n\n");
  354. fflush(stdout);
  355. PerformanceHeader();
  356. Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), t[0]);
  357. Performance("8 bits on Matrix-Shaper ", SpeedTest8bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), t[1]);
  358. Performance("8 bits on same MatrixSh ", SpeedTest8bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), t[2]);
  359. Performance("8 bits on curves ", SpeedTest8bitsRGB, 0, "*curves", "*curves", sizeof(Scanline_rgb8bits), t[3]);
  360. cmsDeleteContext(noPlugin);
  361. }
  362. static
  363. void SpeedTest16(void)
  364. {
  365. cmsContext noPlugin = cmsCreateContext(0, 0);
  366. cmsFloat64Number t[10];
  367. trace("\n\n");
  368. trace("P E R F O R M A N C E T E S T S 1 6 B I T S (D E F A U L T)\n");
  369. trace("=================================================================\n\n");
  370. PerformanceHeader();
  371. t[0] = Performance("16 bits on CLUT profiles ", SpeedTest16bitsRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgb16bits), 0);
  372. t[1] = Performance("16 bits on Matrix-Shaper profiles", SpeedTest16bitsRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgb16bits), 0);
  373. t[2] = Performance("16 bits on same Matrix-Shaper ", SpeedTest16bitsRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgb16bits), 0);
  374. t[3] = Performance("16 bits on curves ", SpeedTest16bitsRGB, noPlugin, "*curves", "*curves", sizeof(Scanline_rgb16bits), 0);
  375. t[4] = Performance("16 bits on CMYK CLUT profiles ", SpeedTest16bitsCMYK, noPlugin, "test1.icc", "test2.icc", sizeof(Scanline_cmyk16bits), 0);
  376. trace("\n\n");
  377. trace("P E R F O R M A N C E T E S T S 1 6 B I T S (P L U G I N)\n");
  378. trace("===============================================================\n\n");
  379. PerformanceHeader();
  380. Performance("16 bits on CLUT profiles ", SpeedTest16bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb16bits), t[0]);
  381. Performance("16 bits on Matrix-Shaper profiles", SpeedTest16bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb16bits), t[1]);
  382. Performance("16 bits on same Matrix-Shaper ", SpeedTest16bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb16bits), t[2]);
  383. Performance("16 bits on curves ", SpeedTest16bitsRGB, 0, "*curves", "*curves", sizeof(Scanline_rgb16bits), t[3]);
  384. Performance("16 bits on CMYK CLUT profiles ", SpeedTest16bitsCMYK, 0, "test1.icc", "test2.icc", sizeof(Scanline_cmyk16bits), t[4]);
  385. }
  386. typedef struct
  387. {
  388. Scanline_rgba8bits pixels[256][256];
  389. cmsUInt8Number padding[4];
  390. } padded_line;
  391. typedef struct
  392. {
  393. padded_line line[256];
  394. } big_bitmap;
  395. static
  396. cmsFloat64Number SpeedTest8bitDoTransform(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  397. {
  398. cmsInt32Number r, g, b, j;
  399. cmsFloat64Number diff;
  400. cmsHTRANSFORM hlcmsxform;
  401. big_bitmap* In;
  402. big_bitmap* Out;
  403. cmsUInt32Number Mb;
  404. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  405. Fail("Unable to open profiles");
  406. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  407. cmsCloseProfile(hlcmsProfileIn);
  408. cmsCloseProfile(hlcmsProfileOut);
  409. // Our test bitmap is 256 x 256 padded lines
  410. Mb = sizeof(big_bitmap);
  411. In = (big_bitmap*)malloc(Mb);
  412. Out = (big_bitmap*)malloc(Mb);
  413. for (r = 0; r < 256; r++)
  414. for (g = 0; g < 256; g++)
  415. for (b = 0; b < 256; b++) {
  416. In->line[r].pixels[g][b].r = (cmsUInt8Number)r;
  417. In->line[r].pixels[g][b].g = (cmsUInt8Number)g;
  418. In->line[r].pixels[g][b].b = (cmsUInt8Number)b;
  419. In->line[r].pixels[g][b].a = 0;
  420. }
  421. MeasureTimeStart();
  422. for (j = 0; j < 256; j++) {
  423. cmsDoTransform(hlcmsxform, In->line[j].pixels, Out->line[j].pixels, 256 * 256);
  424. }
  425. diff = MeasureTimeStop();
  426. free(In); free(Out);
  427. cmsDeleteTransform(hlcmsxform);
  428. return MPixSec(diff);
  429. }
  430. static
  431. cmsFloat64Number SpeedTest8bitLineStride(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut)
  432. {
  433. cmsInt32Number r, g, b;
  434. cmsFloat64Number diff;
  435. cmsHTRANSFORM hlcmsxform;
  436. big_bitmap* In;
  437. big_bitmap* Out;
  438. cmsUInt32Number Mb;
  439. if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL)
  440. Fail("Unable to open profiles");
  441. hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE);
  442. cmsCloseProfile(hlcmsProfileIn);
  443. cmsCloseProfile(hlcmsProfileOut);
  444. // Our test bitmap is 256 x 256 padded lines
  445. Mb = sizeof(big_bitmap);
  446. In = (big_bitmap*)malloc(Mb);
  447. Out = (big_bitmap*)malloc(Mb);
  448. for (r = 0; r < 256; r++)
  449. for (g = 0; g < 256; g++)
  450. for (b = 0; b < 256; b++) {
  451. In->line[r].pixels[g][b].r = (cmsUInt8Number)r;
  452. In->line[r].pixels[g][b].g = (cmsUInt8Number)g;
  453. In->line[r].pixels[g][b].b = (cmsUInt8Number)b;
  454. In->line[r].pixels[g][b].a = 0;
  455. }
  456. MeasureTimeStart();
  457. cmsDoTransformLineStride(hlcmsxform, In, Out, 256*256, 256, sizeof(padded_line), sizeof(padded_line), 0, 0);
  458. diff = MeasureTimeStop();
  459. free(In); free(Out);
  460. cmsDeleteTransform(hlcmsxform);
  461. return MPixSec(diff);
  462. }
  463. static
  464. void ComparativeLineStride8bits(void)
  465. {
  466. cmsContext NoPlugin, Plugin;
  467. trace("\n\n");
  468. trace("C O M P A R A T I V E cmsDoTransform() vs. cmsDoTransformLineStride()\n");
  469. trace(" values given in MegaPixels per second.\n");
  470. trace("====================================================================\n");
  471. fflush(stdout);
  472. NoPlugin = cmsCreateContext(NULL, NULL);
  473. Plugin = cmsCreateContext(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, 0), NULL);
  474. ComparativeCt(NoPlugin, Plugin, "CLUT profiles ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test5.icc", "test3.icc");
  475. ComparativeCt(NoPlugin, Plugin, "CLUT 16 bits ", SpeedTest16bitsRGB, SpeedTest16bitsRGB, "test5.icc", "test3.icc");
  476. ComparativeCt(NoPlugin, Plugin, "Matrix-Shaper ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test5.icc", "test0.icc");
  477. ComparativeCt(NoPlugin, Plugin, "same MatrixSh ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test0.icc", "test0.icc");
  478. ComparativeCt(NoPlugin, Plugin, "curves ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, NULL, NULL);
  479. cmsDeleteContext(Plugin);
  480. cmsDeleteContext(NoPlugin);
  481. }
  482. // The harness test
  483. int main()
  484. {
  485. trace("Multithreaded extensions testbed - 1.0\n");
  486. trace("Copyright (c) 1998-2022 Marti Maria Saguer, all rights reserved\n");
  487. trace("\nInstalling error logger ... ");
  488. cmsSetLogErrorHandler(FatalErrorQuit);
  489. trace("done.\n");
  490. trace("Installing plug-in ... ");
  491. cmsPlugin(cmsThreadedExtensions(CMS_THREADED_GUESS_MAX_THREADS, 0));
  492. trace("done.\n\n");
  493. // Change format
  494. CheckChangeFormat();
  495. // Check speed
  496. SpeedTest8();
  497. SpeedTest16();
  498. ComparativeLineStride8bits();
  499. trace("\nAll tests passed OK\n");
  500. return 0;
  501. }