Created
August 24, 2020 05:54
-
-
Save yoya/564a34e9f317ec85c9f94470b867c187 to your computer and use it in GitHub Desktop.
lcms2 の plugins/fast_float/fast_float_testbed.c から macOS で failed する要素を抜いたもの
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//--------------------------------------------------------------------------------- | |
// | |
// Little Color Management System, fast floating point extensions | |
// Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved | |
// | |
// | |
// This program is free software: you can redistribute it and/or modify | |
// it under the terms of the GNU General Public License as published by | |
// the Free Software Foundation, either version 3 of the License, or | |
// (at your option) any later version. | |
// | |
// This program is distributed in the hope that it will be useful, | |
// but WITHOUT ANY WARRANTY; without even the implied warranty of | |
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
// GNU General Public License for more details. | |
// | |
// You should have received a copy of the GNU General Public License | |
// along with this program. If not, see <http://www.gnu.org/licenses/>. | |
// | |
//--------------------------------------------------------------------------------- | |
#include "fast_float_internal.h" | |
#include <stdlib.h> | |
#include <memory.h> | |
// Some pixel representations | |
typedef struct { cmsUInt8Number r, g, b; } Scanline_rgb8bits; | |
typedef struct { cmsUInt8Number r, g, b, a; } Scanline_rgba8bits; | |
typedef struct { cmsUInt16Number r, g, b; } Scanline_rgb16bits; | |
typedef struct { cmsUInt16Number r, g, b, a; } Scanline_rgba16bits; | |
typedef struct { cmsUInt16Number r, g, b; } Scanline_rgb15bits; | |
typedef struct { cmsUInt16Number r, g, b, a; } Scanline_rgba15bits; | |
typedef struct { cmsUInt16Number r, g, b, a; } Scanline_cmyk15bits; | |
typedef struct { cmsFloat32Number r, g, b; } Scanline_rgbFloat; | |
typedef struct { cmsFloat32Number r, g, b, a; } Scanline_rgbaFloat; | |
// 15 bit mode. <=> 8 bits mode | |
#define FROM_8_TO_15(x8) (cmsUInt16Number) ((((cmsUInt64Number)x8 << 15)) / 0xFF) | |
#define FROM_15_TO_8(x15) (cmsUInt8Number) (((cmsUInt64Number) x15 * 0xFF + 0x4000) >> 15) | |
// Floating point acuracy for tests | |
#define EPSILON_FLOAT_TESTS 0.005 | |
// The callback function used by cmsSetLogErrorHandler() | |
static | |
void FatalErrorQuit(cmsContext ContextID, cmsUInt32Number ErrorCode, const char *Text) | |
{ | |
UNUSED_PARAMETER(ContextID); | |
UNUSED_PARAMETER(ErrorCode); | |
printf("** Fatal error: %s\n", Text); | |
exit(1); | |
} | |
// Rise an error and exit | |
static | |
void Fail(const char* frm, ...) | |
{ | |
char ReasonToFailBuffer[1024]; | |
va_list args; | |
va_start(args, frm); | |
vsprintf(ReasonToFailBuffer, frm, args); | |
FatalErrorQuit(0, 0, ReasonToFailBuffer); | |
// unreacheable va_end(args); | |
} | |
// Creates a fake profile that only has a curve. Used in several places | |
static | |
cmsHPROFILE CreateCurves(void) | |
{ | |
cmsToneCurve* Gamma = cmsBuildGamma(0, 1.1); | |
cmsToneCurve* Transfer[3]; | |
cmsHPROFILE h; | |
Transfer[0] = Transfer[1] = Transfer[2] = Gamma; | |
h = cmsCreateLinearizationDeviceLink(cmsSigRgbData, Transfer); | |
cmsFreeToneCurve(Gamma); | |
return h; | |
} | |
// Check for a single 15 bit Photoshop-like formatter | |
static | |
void CheckSingleFormatter15(cmsContext id, cmsUInt32Number Type, const char* Text) | |
{ | |
cmsUInt16Number Values[cmsMAXCHANNELS]; | |
cmsUInt8Number Buffer[1024]; | |
cmsFormatter f, b; | |
cmsInt32Number i, j, nChannels, bytes; | |
_xform_head info; | |
UNUSED_PARAMETER(id); | |
memset(&info, 0, sizeof(info)); | |
info.OutputFormat = info.InputFormat = Type; | |
// Get functions to go forth and back | |
f = Formatter_15Bit_Factory(Type, cmsFormatterInput, CMS_PACK_FLAGS_16BITS); | |
b = Formatter_15Bit_Factory(Type, cmsFormatterOutput, CMS_PACK_FLAGS_16BITS); | |
if (f.Fmt16 == NULL || b.Fmt16 == NULL) { | |
Fail("no formatter for %s", Text); | |
return; | |
} | |
nChannels = T_CHANNELS(Type); | |
bytes = T_BYTES(Type); | |
for (j = 0; j < 5; j++) { | |
for (i = 0; i < nChannels; i++) { | |
Values[i] = (cmsUInt16Number)(i + j) << 1; | |
} | |
b.Fmt16((struct _cmstransform_struct*) &info, Values, Buffer, 1); | |
memset(Values, 0, sizeof(Values)); | |
f.Fmt16((struct _cmstransform_struct*) &info, Values, Buffer, 1); | |
for (i = 0; i < nChannels; i++) { | |
if (Values[i] != ((i + j) << 1)) { | |
Fail("%s failed", Text); | |
return; | |
} | |
} | |
} | |
} | |
#define C(a) CheckSingleFormatter15(0, a, #a) | |
// Check for all 15 bits formatters | |
static | |
void CheckFormatters15(void) | |
{ | |
C(TYPE_GRAY_15); | |
C(TYPE_GRAY_15_REV); | |
C(TYPE_GRAY_15_SE); | |
C(TYPE_GRAYA_15); | |
C(TYPE_GRAYA_15_SE); | |
C(TYPE_GRAYA_15_PLANAR); | |
C(TYPE_RGB_15); | |
C(TYPE_RGB_15_PLANAR); | |
C(TYPE_RGB_15_SE); | |
C(TYPE_BGR_15); | |
C(TYPE_BGR_15_PLANAR); | |
C(TYPE_BGR_15_SE); | |
C(TYPE_RGBA_15); | |
C(TYPE_RGBA_15_PLANAR); | |
C(TYPE_RGBA_15_SE); | |
C(TYPE_ARGB_15); | |
C(TYPE_ABGR_15); | |
C(TYPE_ABGR_15_PLANAR); | |
C(TYPE_ABGR_15_SE); | |
C(TYPE_BGRA_15); | |
C(TYPE_BGRA_15_SE); | |
C(TYPE_YMC_15), | |
C(TYPE_CMY_15); | |
C(TYPE_CMY_15_PLANAR); | |
C(TYPE_CMY_15_SE); | |
C(TYPE_CMYK_15); | |
C(TYPE_CMYK_15_REV); | |
C(TYPE_CMYK_15_PLANAR); | |
C(TYPE_CMYK_15_SE); | |
C(TYPE_KYMC_15); | |
C(TYPE_KYMC_15_SE); | |
C(TYPE_KCMY_15); | |
C(TYPE_KCMY_15_REV); | |
C(TYPE_KCMY_15_SE); | |
} | |
#undef C | |
static | |
cmsInt32Number checkSingleComputeIncrements(cmsUInt32Number Format, cmsUInt32Number planeStride, cmsUInt32Number ExpectedChannels, cmsUInt32Number ExpectedAlpha, ...) | |
{ | |
cmsUInt32Number nChannels, nAlpha, nTotal, i, rc = 0 ; | |
cmsUInt32Number ComponentStartingOrder[cmsMAXCHANNELS], ComponentPointerIncrements[cmsMAXCHANNELS]; | |
va_list args; | |
va_start(args, ExpectedAlpha); | |
_cmsComputeComponentIncrements(Format, planeStride, &nChannels, &nAlpha, ComponentStartingOrder, ComponentPointerIncrements); | |
if (nChannels != ExpectedChannels) | |
return 0; | |
if (nAlpha != ExpectedAlpha) | |
return 0; | |
nTotal = nAlpha + nChannels; | |
for (i = 0; i < nTotal; i++) | |
{ | |
cmsUInt32Number so = va_arg(args, cmsUInt32Number); | |
if (so != ComponentStartingOrder[i]) | |
goto Error; | |
} | |
for (i = 0; i < nTotal; i++) | |
{ | |
cmsUInt32Number so = va_arg(args, cmsUInt32Number); | |
if (so != ComponentPointerIncrements[i]) | |
goto Error; | |
} | |
// Success | |
rc = 1; | |
Error: | |
va_end(args); | |
return rc; | |
} | |
#define CHECK(frm, plane, chans, alpha, ...) if (!checkSingleComputeIncrements(frm, plane, chans, alpha, __VA_ARGS__)) { printf("Format failed!\n"); return 0; } | |
// Validate the compute increments function | |
cmsInt32Number CheckComputeIncrements(void) | |
{ | |
CHECK(TYPE_GRAY_8, 0, 1, 0, /**/ 0, /**/ 1); | |
CHECK(TYPE_GRAYA_8, 0, 1, 1, /**/ 0, 1, /**/ 2, 2); | |
CHECK(TYPE_AGRAY_8, 0, 1, 1, /**/ 1, 0, /**/ 2, 2); | |
CHECK(TYPE_GRAY_16, 0, 1, 0, /**/ 0, /**/ 2); | |
CHECK(TYPE_GRAYA_16, 0, 1, 1, /**/ 0, 2, /**/ 4, 4); | |
CHECK(TYPE_AGRAY_16, 0, 1, 1, /**/ 2, 0, /**/ 4, 4); | |
CHECK(TYPE_GRAY_FLT, 0, 1, 0, /**/ 0, /**/ 4); | |
CHECK(TYPE_GRAYA_FLT, 0, 1, 1, /**/ 0, 4, /**/ 8, 8); | |
CHECK(TYPE_AGRAY_FLT, 0, 1, 1, /**/ 4, 0, /**/ 8, 8); | |
CHECK(TYPE_GRAY_DBL, 0, 1, 0, /**/ 0, /**/ 8); | |
CHECK(TYPE_AGRAY_DBL, 0, 1, 1, /**/ 8, 0, /**/ 16, 16); | |
CHECK(TYPE_RGB_8, 0, 3, 0, /**/ 0, 1, 2, /**/ 3, 3, 3); | |
CHECK(TYPE_RGBA_8, 0, 3, 1, /**/ 0, 1, 2, 3, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_ARGB_8, 0, 3, 1, /**/ 1, 2, 3, 0, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_RGB_16, 0, 3, 0, /**/ 0, 2, 4, /**/ 6, 6, 6); | |
CHECK(TYPE_RGBA_16, 0, 3, 1, /**/ 0, 2, 4, 6, /**/ 8, 8, 8, 8); | |
CHECK(TYPE_ARGB_16, 0, 3, 1, /**/ 2, 4, 6, 0, /**/ 8, 8, 8, 8); | |
CHECK(TYPE_RGB_FLT, 0, 3, 0, /**/ 0, 4, 8, /**/ 12, 12, 12); | |
CHECK(TYPE_RGBA_FLT, 0, 3, 1, /**/ 0, 4, 8, 12, /**/ 16, 16, 16, 16); | |
CHECK(TYPE_ARGB_FLT, 0, 3, 1, /**/ 4, 8, 12, 0, /**/ 16, 16, 16, 16); | |
CHECK(TYPE_BGR_8, 0, 3, 0, /**/ 2, 1, 0, /**/ 3, 3, 3); | |
CHECK(TYPE_BGRA_8, 0, 3, 1, /**/ 2, 1, 0, 3, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_ABGR_8, 0, 3, 1, /**/ 3, 2, 1, 0, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_BGR_16, 0, 3, 0, /**/ 4, 2, 0, /**/ 6, 6, 6); | |
CHECK(TYPE_BGRA_16, 0, 3, 1, /**/ 4, 2, 0, 6, /**/ 8, 8, 8, 8); | |
CHECK(TYPE_ABGR_16, 0, 3, 1, /**/ 6, 4, 2, 0, /**/ 8, 8, 8, 8); | |
CHECK(TYPE_BGR_FLT, 0, 3, 0, /**/ 8, 4, 0, /**/ 12, 12, 12); | |
CHECK(TYPE_BGRA_FLT, 0, 3, 1, /**/ 8, 4, 0, 12, /**/ 16, 16, 16, 16); | |
CHECK(TYPE_ABGR_FLT, 0, 3, 1, /**/ 12, 8, 4, 0, /**/ 16, 16, 16, 16); | |
CHECK(TYPE_CMYK_8, 0, 4, 0, /**/ 0, 1, 2, 3, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_CMYKA_8, 0, 4, 1, /**/ 0, 1, 2, 3, 4, /**/ 5, 5, 5, 5, 5); | |
CHECK(TYPE_ACMYK_8, 0, 4, 1, /**/ 1, 2, 3, 4, 0, /**/ 5, 5, 5, 5, 5); | |
CHECK(TYPE_KYMC_8, 0, 4, 0, /**/ 3, 2, 1, 0, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_KYMCA_8, 0, 4, 1, /**/ 3, 2, 1, 0, 4, /**/ 5, 5, 5, 5, 5); | |
CHECK(TYPE_AKYMC_8, 0, 4, 1, /**/ 4, 3, 2, 1, 0, /**/ 5, 5, 5, 5, 5); | |
CHECK(TYPE_KCMY_8, 0, 4, 0, /**/ 1, 2, 3, 0, /**/ 4, 4, 4, 4); | |
CHECK(TYPE_CMYK_16, 0, 4, 0, /**/ 0, 2, 4, 6, /**/ 8, 8, 8, 8); | |
CHECK(TYPE_CMYKA_16, 0, 4, 1, /**/ 0, 2, 4, 6, 8, /**/ 10, 10, 10, 10, 10); | |
CHECK(TYPE_ACMYK_16, 0, 4, 1, /**/ 2, 4, 6, 8, 0, /**/ 10, 10, 10, 10, 10); | |
CHECK(TYPE_KYMC_16, 0, 4, 0, /**/ 6, 4, 2, 0, /**/ 8, 8, 8, 8); | |
CHECK(TYPE_KYMCA_16, 0, 4, 1, /**/ 6, 4, 2, 0, 8, /**/ 10, 10, 10, 10, 10); | |
CHECK(TYPE_AKYMC_16, 0, 4, 1, /**/ 8, 6, 4, 2, 0, /**/ 10, 10, 10, 10, 10); | |
CHECK(TYPE_KCMY_16, 0, 4, 0, /**/ 2, 4, 6, 0, /**/ 8, 8, 8, 8); | |
// Planar | |
CHECK(TYPE_GRAYA_8_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 1, 1); | |
CHECK(TYPE_AGRAY_8_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 1, 1); | |
CHECK(TYPE_GRAYA_16_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 2, 2); | |
CHECK(TYPE_AGRAY_16_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 2, 2); | |
CHECK(TYPE_GRAYA_FLT_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 4, 4); | |
CHECK(TYPE_AGRAY_FLT_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 4, 4); | |
CHECK(TYPE_GRAYA_DBL_PLANAR, 100, 1, 1, /**/ 0, 100, /**/ 8, 8); | |
CHECK(TYPE_AGRAY_DBL_PLANAR, 100, 1, 1, /**/ 100, 0, /**/ 8, 8); | |
CHECK(TYPE_RGB_8_PLANAR, 100, 3, 0, /**/ 0, 100, 200, /**/ 1, 1, 1); | |
CHECK(TYPE_RGBA_8_PLANAR, 100, 3, 1, /**/ 0, 100, 200, 300, /**/ 1, 1, 1, 1); | |
CHECK(TYPE_ARGB_8_PLANAR, 100, 3, 1, /**/ 100, 200, 300, 0, /**/ 1, 1, 1, 1); | |
CHECK(TYPE_BGR_8_PLANAR, 100, 3, 0, /**/ 200, 100, 0, /**/ 1, 1, 1); | |
CHECK(TYPE_BGRA_8_PLANAR, 100, 3, 1, /**/ 200, 100, 0, 300, /**/ 1, 1, 1, 1); | |
CHECK(TYPE_ABGR_8_PLANAR, 100, 3, 1, /**/ 300, 200, 100, 0, /**/ 1, 1, 1, 1); | |
CHECK(TYPE_RGB_16_PLANAR, 100, 3, 0, /**/ 0, 100, 200, /**/ 2, 2, 2); | |
CHECK(TYPE_RGBA_16_PLANAR, 100, 3, 1, /**/ 0, 100, 200, 300, /**/ 2, 2, 2, 2); | |
CHECK(TYPE_ARGB_16_PLANAR, 100, 3, 1, /**/ 100, 200, 300, 0, /**/ 2, 2, 2, 2); | |
CHECK(TYPE_BGR_16_PLANAR, 100, 3, 0, /**/ 200, 100, 0, /**/ 2, 2, 2); | |
CHECK(TYPE_BGRA_16_PLANAR, 100, 3, 1, /**/ 200, 100, 0, 300, /**/ 2, 2, 2, 2); | |
CHECK(TYPE_ABGR_16_PLANAR, 100, 3, 1, /**/ 300, 200, 100, 0, /**/ 2, 2, 2, 2); | |
return 1; | |
} | |
// Check 15 bit mode accuracy | |
static | |
cmsBool Valid15(cmsUInt16Number a, cmsUInt8Number b) | |
{ | |
return abs(FROM_15_TO_8(a) - b) <= 2; | |
} | |
// Check the test macros itselves | |
static | |
void Check15bitMacros(void) | |
{ | |
int i; | |
printf("Checking 15 bit <=> 8 bit macros..."); | |
for (i = 0; i < 256; i++) | |
{ | |
cmsUInt16Number n = FROM_8_TO_15(i); | |
cmsUInt8Number m = FROM_15_TO_8(n); | |
if (m != i) | |
Fail("Failed on %d (->%d->%d)", i, n, m); | |
} | |
printf("ok\n"); | |
} | |
// Do an in-depth test by checking all RGB cube of 8 bits, going from profilein to profileout. | |
// Results should be same except for 2 contone levels allowed for roundoff. Note 15 bits is more | |
// precise than 8 bits and this is a source of discrepancies. Cache is disabled | |
static | |
void TryAllValues15(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent) | |
{ | |
Scanline_rgb8bits* buffer8in; | |
Scanline_rgb15bits* buffer15in; | |
Scanline_rgb8bits* buffer8out; | |
Scanline_rgb15bits* buffer15out; | |
int r, g, b, j; | |
cmsUInt32Number npixels = 256 * 256 * 256; // All RGB cube in 8 bits | |
cmsHTRANSFORM xform15 = cmsCreateTransformTHR(0, hlcmsProfileIn, TYPE_RGB_15, hlcmsProfileOut, TYPE_RGB_15, Intent, cmsFLAGS_NOCACHE); | |
cmsHTRANSFORM xform8 = cmsCreateTransformTHR(0, hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, Intent, cmsFLAGS_NOCACHE); // Transforms already created | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
if (xform15 == NULL || xform8 == NULL) { | |
Fail("NULL transforms on check for 15 bit conversions"); | |
} | |
// Since this is just a test, I will not check memory allocation... | |
buffer8in = (Scanline_rgb8bits*)malloc(npixels * sizeof(Scanline_rgb8bits)); | |
buffer15in = (Scanline_rgb15bits*)malloc(npixels * sizeof(Scanline_rgb15bits)); | |
buffer8out = (Scanline_rgb8bits*)malloc(npixels * sizeof(Scanline_rgb8bits)); | |
buffer15out = (Scanline_rgb15bits*)malloc(npixels * sizeof(Scanline_rgb15bits)); | |
// Fill input values for 8 and 15 bits | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
buffer8in[j].r = (cmsUInt8Number)r; | |
buffer8in[j].g = (cmsUInt8Number)g; | |
buffer8in[j].b = (cmsUInt8Number)b; | |
buffer15in[j].r = FROM_8_TO_15(r); | |
buffer15in[j].g = FROM_8_TO_15(g); | |
buffer15in[j].b = FROM_8_TO_15(b); | |
j++; | |
} | |
cmsDoTransform(xform15, buffer15in, buffer15out, npixels); | |
cmsDoTransform(xform8, buffer8in, buffer8out, npixels); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
// Check the results | |
if (!Valid15(buffer15out[j].r, buffer8out[j].r) || | |
!Valid15(buffer15out[j].g, buffer8out[j].g) || | |
!Valid15(buffer15out[j].b, buffer8out[j].b)) | |
Fail("Conversion failed at (%d %d %d) != (%d %d %d)", buffer8out[j].r, buffer8out[j].g, buffer8out[j].b, | |
FROM_15_TO_8(buffer15out[j].r), FROM_15_TO_8(buffer15out[j].g), FROM_15_TO_8(buffer15out[j].b)); | |
j++; | |
} | |
free(buffer8in); free(buffer15in); | |
free(buffer8out); free(buffer15out); | |
cmsDeleteTransform(xform15); | |
cmsDeleteTransform(xform8); | |
} | |
// Convert some known values | |
static | |
void Check15bitsConversions(void) | |
{ | |
Check15bitMacros(); | |
printf("Checking accuracy of 15 bits on CLUT..."); | |
TryAllValues15(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
printf("Checking accuracy of 15 bits on same profile ..."); | |
TryAllValues15(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
printf("Checking accuracy of 15 bits on Matrix..."); | |
TryAllValues15(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
printf("All 15 bits tests passed OK\n\n"); | |
} | |
// Next test checks results of optimized 16 bits versus raw 16 bits. | |
static | |
void TryAllValues16bits(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent) | |
{ | |
cmsContext Raw = cmsCreateContext(NULL, NULL); | |
cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL); | |
Scanline_rgba16bits* bufferIn; | |
Scanline_rgba16bits* bufferRawOut; | |
Scanline_rgba16bits* bufferPluginOut; | |
int r, g, b; | |
int j; | |
cmsUInt32Number npixels = 256 * 256 * 256; | |
cmsHTRANSFORM xformRaw = cmsCreateTransformTHR(Raw, hlcmsProfileIn, TYPE_RGBA_16, hlcmsProfileOut, TYPE_RGBA_16, Intent, cmsFLAGS_NOCACHE| cmsFLAGS_COPY_ALPHA); | |
cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGBA_16, hlcmsProfileOut, TYPE_RGBA_16, Intent, cmsFLAGS_NOCACHE| cmsFLAGS_COPY_ALPHA); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
if (xformRaw == NULL || xformPlugin == NULL) { | |
Fail("NULL transforms on check float conversions"); | |
} | |
// Again, no checking on mem alloc because this is just a test | |
bufferIn = (Scanline_rgba16bits*)malloc(npixels * sizeof(Scanline_rgba16bits)); | |
bufferRawOut = (Scanline_rgba16bits*)malloc(npixels * sizeof(Scanline_rgba16bits)); | |
bufferPluginOut = (Scanline_rgba16bits*)malloc(npixels * sizeof(Scanline_rgba16bits)); | |
// Same input to both transforms | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
bufferIn[j].r = FROM_8_TO_16(0xf8); | |
bufferIn[j].g = FROM_8_TO_16(0xf8); | |
bufferIn[j].b = FROM_8_TO_16(0xf8); | |
bufferIn[j].a = 0xffff; | |
j++; | |
} | |
// Different transforms, different output buffers | |
cmsDoTransform(xformRaw, bufferIn, bufferRawOut, npixels); | |
cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels); | |
#if 1 | |
// Lets compare results | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
if (bufferRawOut[j].r != bufferPluginOut[j].r || | |
bufferRawOut[j].g != bufferPluginOut[j].g || | |
bufferRawOut[j].b != bufferPluginOut[j].b || | |
bufferRawOut[j].a != bufferPluginOut[j].a) | |
Fail( | |
"Conversion failed at [%x %x %x %x] (%x %x %x %x) != (%x %x %x %x)", | |
bufferIn[j].r, bufferIn[j].g, bufferIn[j].b, bufferIn[j].a, | |
bufferRawOut[j].r, bufferRawOut[j].g, bufferRawOut[j].b, bufferRawOut[j].a, | |
bufferPluginOut[j].r, bufferPluginOut[j].g, bufferPluginOut[j].b, bufferPluginOut[j].a); | |
j++; | |
} | |
#endif | |
free(bufferIn); free(bufferRawOut); | |
free(bufferPluginOut); | |
cmsDeleteTransform(xformRaw); | |
cmsDeleteTransform(xformPlugin); | |
cmsDeleteContext(Plugin); | |
cmsDeleteContext(Raw); | |
} | |
static | |
void CheckAccuracy16Bits(void) | |
{ | |
// CLUT should be as 16 bits or better | |
printf("Checking accuracy of 16 bits CLUT..."); | |
TryAllValues16bits(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL); | |
printf("All 16 bits tests passed OK\n\n"); | |
} | |
// -------------------------------------------------------------------------------------------------- | |
// A C C U R A C Y C H E C K S | |
// -------------------------------------------------------------------------------------------------- | |
// Check result accuracy | |
static | |
cmsBool ValidFloat(cmsFloat32Number a, cmsFloat32Number b) | |
{ | |
return fabsf(a-b) < EPSILON_FLOAT_TESTS; | |
} | |
// Do an in-depth test by checking all RGB cube of 8 bits, going from profilein to profileout. | |
// Values with and without optimization are checked (different contexts, one with the plugin and another without) | |
// Results should be same except for EPSILON_FLOAT_TESTS allowed for accuracy/speed tradeoff. Cache is disabled | |
static | |
void TryAllValuesFloat(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent) | |
{ | |
cmsContext Raw = cmsCreateContext(NULL, NULL); | |
cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL); | |
Scanline_rgbFloat* bufferIn; | |
Scanline_rgbFloat* bufferRawOut; | |
Scanline_rgbFloat* bufferPluginOut; | |
int r, g, b; | |
int j; | |
cmsUInt32Number npixels = 256 * 256 * 256; | |
cmsHTRANSFORM xformRaw = cmsCreateTransformTHR(Raw, hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, cmsFLAGS_NOCACHE); | |
cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
if (xformRaw == NULL || xformPlugin == NULL) { | |
Fail("NULL transforms on check float conversions"); | |
} | |
// Again, no checking on mem alloc because this is just a test | |
bufferIn = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat)); | |
bufferRawOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat)); | |
bufferPluginOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat)); | |
// Same input to both transforms | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
bufferIn[j].r = (cmsFloat32Number)r / 255.0f; | |
bufferIn[j].g = (cmsFloat32Number)g / 255.0f; | |
bufferIn[j].b = (cmsFloat32Number)b / 255.0f; | |
j++; | |
} | |
// Different transforms, different output buffers | |
cmsDoTransform(xformRaw, bufferIn, bufferRawOut, npixels); | |
cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels); | |
// Lets compare results | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
if (!ValidFloat(bufferRawOut[j].r, bufferPluginOut[j].r) || | |
!ValidFloat(bufferRawOut[j].g, bufferPluginOut[j].g) || | |
!ValidFloat(bufferRawOut[j].b, bufferPluginOut[j].b)) | |
Fail("Conversion failed at (%f %f %f) != (%f %f %f)", bufferRawOut[j].r, bufferRawOut[j].g, bufferRawOut[j].b, | |
bufferPluginOut[j].r, bufferPluginOut[j].g, bufferPluginOut[j].b); | |
j++; | |
} | |
free(bufferIn); free(bufferRawOut); | |
free(bufferPluginOut); | |
cmsDeleteTransform(xformRaw); | |
cmsDeleteTransform(xformPlugin); | |
cmsDeleteContext(Plugin); | |
cmsDeleteContext(Raw); | |
} | |
static | |
void TryAllValuesFloatAlpha(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent) | |
{ | |
cmsContext Raw = cmsCreateContext(NULL, NULL); | |
cmsContext Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL); | |
Scanline_rgbaFloat* bufferIn; | |
Scanline_rgbaFloat* bufferRawOut; | |
Scanline_rgbaFloat* bufferPluginOut; | |
int r, g, b; | |
int j; | |
cmsUInt32Number npixels = 256 * 256 * 256; | |
cmsHTRANSFORM xformRaw = cmsCreateTransformTHR(Raw, hlcmsProfileIn, TYPE_RGBA_FLT, hlcmsProfileOut, TYPE_RGBA_FLT, Intent, cmsFLAGS_NOCACHE); | |
cmsHTRANSFORM xformPlugin = cmsCreateTransformTHR(Plugin, hlcmsProfileIn, TYPE_RGBA_FLT, hlcmsProfileOut, TYPE_RGBA_FLT, Intent, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
if (xformRaw == NULL || xformPlugin == NULL) { | |
Fail("NULL transforms on check float conversions"); | |
} | |
// Again, no checking on mem alloc because this is just a test | |
bufferIn = (Scanline_rgbaFloat*)malloc(npixels * sizeof(Scanline_rgbaFloat)); | |
bufferRawOut = (Scanline_rgbaFloat*)malloc(npixels * sizeof(Scanline_rgbaFloat)); | |
bufferPluginOut = (Scanline_rgbaFloat*)malloc(npixels * sizeof(Scanline_rgbaFloat)); | |
// Same input to both transforms | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
bufferIn[j].r = (cmsFloat32Number)r / 255.0f; | |
bufferIn[j].g = (cmsFloat32Number)g / 255.0f; | |
bufferIn[j].b = (cmsFloat32Number)b / 255.0f; | |
bufferIn[j].a = (cmsFloat32Number) 1.0f; | |
j++; | |
} | |
// Different transforms, different output buffers | |
cmsDoTransform(xformRaw, bufferIn, bufferRawOut, npixels); | |
cmsDoTransform(xformPlugin, bufferIn, bufferPluginOut, npixels); | |
#if 1 | |
// Lets compare results | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
if (!ValidFloat(bufferRawOut[j].r, bufferPluginOut[j].r) || | |
!ValidFloat(bufferRawOut[j].g, bufferPluginOut[j].g) || | |
!ValidFloat(bufferRawOut[j].b, bufferPluginOut[j].b) || | |
!ValidFloat(bufferRawOut[j].a, bufferPluginOut[j].a)) | |
Fail("Conversion failed at (%f %f %f %f) != (%f %f %f %f)", bufferRawOut[j].r, bufferRawOut[j].g, bufferRawOut[j].b, bufferRawOut[j].a, | |
bufferPluginOut[j].r, bufferPluginOut[j].g, bufferPluginOut[j].b, bufferPluginOut[j].a); | |
j++; | |
} | |
#endif | |
free(bufferIn); free(bufferRawOut); | |
free(bufferPluginOut); | |
cmsDeleteTransform(xformRaw); | |
cmsDeleteTransform(xformPlugin); | |
cmsDeleteContext(Plugin); | |
cmsDeleteContext(Raw); | |
} | |
// Next test checks results of optimized floating point versus 16 bits. That is, converting the float to 16 bits, operating | |
// in 16 bits and back to float. Results again should be in range of epsilon | |
static | |
cmsBool Valid16Float(cmsUInt16Number a, cmsFloat32Number b) | |
{ | |
return fabs(((cmsFloat32Number)a / (cmsFloat32Number) 0xFFFF) - b) < EPSILON_FLOAT_TESTS; | |
} | |
// Do an in-depth test by checking all RGB cube of 8 bits, going from profilein to profileout. 16 bits temporary is used as reference | |
static | |
void TryAllValuesFloatVs16(cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut, cmsInt32Number Intent) | |
{ | |
Scanline_rgbFloat* bufferIn; | |
Scanline_rgb16bits* bufferIn16; | |
Scanline_rgbFloat* bufferFloatOut; | |
Scanline_rgb16bits* buffer16Out; | |
int r, g, b; | |
int j; | |
cmsUInt32Number npixels = 256 * 256 * 256; | |
cmsHTRANSFORM xformRaw = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, Intent, cmsFLAGS_NOCACHE); | |
cmsHTRANSFORM xformPlugin = cmsCreateTransform(hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, Intent, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
if (xformRaw == NULL || xformPlugin == NULL) { | |
Fail("NULL transforms on check float vs 16 conversions"); | |
} | |
// Again, no checking on mem alloc because this is just a test | |
bufferIn = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat)); | |
bufferIn16 = (Scanline_rgb16bits*)malloc(npixels * sizeof(Scanline_rgb16bits)); | |
bufferFloatOut = (Scanline_rgbFloat*)malloc(npixels * sizeof(Scanline_rgbFloat)); | |
buffer16Out = (Scanline_rgb16bits*)malloc(npixels * sizeof(Scanline_rgb16bits)); | |
// Fill two equivalent input buffers | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
bufferIn[j].r = (cmsFloat32Number)r / 255.0f; | |
bufferIn[j].g = (cmsFloat32Number)g / 255.0f; | |
bufferIn[j].b = (cmsFloat32Number)b / 255.0f; | |
bufferIn16[j].r = FROM_8_TO_16(r); | |
bufferIn16[j].g = FROM_8_TO_16(g); | |
bufferIn16[j].b = FROM_8_TO_16(b); | |
j++; | |
} | |
// Convert | |
cmsDoTransform(xformRaw, bufferIn16, buffer16Out, npixels); | |
cmsDoTransform(xformPlugin, bufferIn, bufferFloatOut, npixels); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
// Check for same values | |
if (!Valid16Float(buffer16Out[j].r, bufferFloatOut[j].r) || | |
!Valid16Float(buffer16Out[j].g, bufferFloatOut[j].g) || | |
!Valid16Float(buffer16Out[j].b, bufferFloatOut[j].b)) | |
Fail("Conversion failed at (%f %f %f) != (%f %f %f)", buffer16Out[j].r / 65535.0, buffer16Out[j].g / 65535.0, buffer16Out[j].b / 65535.0, | |
bufferFloatOut[j].r, bufferFloatOut[j].g, bufferFloatOut[j].b); | |
j++; | |
} | |
free(bufferIn16); free(buffer16Out); | |
free(bufferIn); free(bufferFloatOut); | |
cmsDeleteTransform(xformRaw); | |
cmsDeleteTransform(xformPlugin); | |
} | |
// Check change format feature | |
static | |
void CheckChangeFormat(void) | |
{ | |
cmsHPROFILE hsRGB, hLab; | |
cmsHTRANSFORM xform; | |
cmsUInt8Number rgb8[3] = { 10, 120, 40 }; | |
cmsUInt16Number rgb16[3] = { 10* 257, 120*257, 40*257 }; | |
cmsUInt16Number lab16_1[3], lab16_2[3]; | |
printf("Checking change format feature..."); | |
hsRGB = cmsCreate_sRGBProfile(); | |
hLab = cmsCreateLab4Profile(NULL); | |
xform = cmsCreateTransform(hsRGB, TYPE_RGB_16, hLab, TYPE_Lab_16, INTENT_PERCEPTUAL, 0); | |
cmsCloseProfile(hsRGB); | |
cmsCloseProfile(hLab); | |
cmsDoTransform(xform, rgb16, lab16_1, 1); | |
cmsChangeBuffersFormat(xform, TYPE_RGB_8, TYPE_Lab_16); | |
cmsDoTransform(xform, rgb8, lab16_2, 1); | |
cmsDeleteTransform(xform); | |
if (memcmp(lab16_1, lab16_2, sizeof(lab16_1)) != 0) | |
Fail("Change format failed!"); | |
printf("Ok\n"); | |
} | |
static | |
cmsBool ValidInt(cmsUInt16Number a, cmsUInt16Number b) | |
{ | |
return abs(a - b) <= 32; | |
} | |
static | |
void CheckLab2Roundtrip(void) | |
{ | |
cmsHPROFILE hsRGB, hLab; | |
cmsHTRANSFORM xform, xform2; | |
cmsInt8Number* lab; | |
cmsInt32Number Mb, j; | |
cmsInt32Number r, g, b; | |
Scanline_rgb8bits* In; | |
Scanline_rgb8bits* Out; | |
printf("Checking lab2 roundtrip..."); | |
hsRGB = cmsCreate_sRGBProfile(); | |
hLab = cmsCreateLab2Profile(NULL); | |
xform = cmsCreateTransform(hsRGB, TYPE_RGB_8, hLab, TYPE_Lab_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE|cmsFLAGS_BLACKPOINTCOMPENSATION); | |
xform2 = cmsCreateTransform(hLab, TYPE_Lab_8, hsRGB, TYPE_RGB_8, INTENT_RELATIVE_COLORIMETRIC, cmsFLAGS_NOOPTIMIZE | cmsFLAGS_BLACKPOINTCOMPENSATION); | |
cmsCloseProfile(hsRGB); | |
cmsCloseProfile(hLab); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgb8bits); | |
In = (Scanline_rgb8bits*)malloc(Mb); | |
Out = (Scanline_rgb8bits*)malloc(Mb); | |
lab = (cmsInt8Number*)malloc(256 * 256 * 256 * 3 * sizeof(cmsInt8Number)); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) | |
{ | |
In[j].r = (cmsUInt8Number)r; | |
In[j].g = (cmsUInt8Number)g; | |
In[j].b = (cmsUInt8Number)b; | |
j++; | |
} | |
cmsDoTransform(xform, In, lab, 256 * 256 * 256); | |
cmsDoTransform(xform2, lab, Out, 256 * 256 * 256); | |
cmsDeleteTransform(xform); | |
cmsDeleteTransform(xform2); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
// Check for same values | |
if (!ValidInt(In[j].r, Out[j].r) || | |
!ValidInt(In[j].g, Out[j].g) || | |
!ValidInt(In[j].b, Out[j].b)) | |
Fail("Conversion failed at (%d %d %d) != (%d %d %d)", In[j].r, In[j].g, In[j].b, | |
Out[j].r, Out[j].g, Out[j].b); | |
j++; | |
} | |
free(In); | |
free(Out); | |
free(lab); | |
printf("Ok\n"); | |
} | |
// Convert some known values | |
static | |
void CheckConversionFloat(void) | |
{ | |
printf("Crash test..."); | |
TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
printf("Crash (II) test..."); | |
// TryAllValuesFloatAlpha(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
// printf("Ok\n"); | |
printf("Skip\n"); | |
// Matrix-shaper should be accurate | |
printf("Checking accuracy on Matrix-shaper..."); | |
TryAllValuesFloat(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
// CLUT should be as 16 bits or better | |
printf("Checking accuracy of CLUT..."); | |
TryAllValuesFloatVs16(cmsOpenProfileFromFile("test5.icc", "r"), cmsOpenProfileFromFile("test3.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
// Same profile should give same values (we test both methods) | |
printf("Checking accuracy on same profile ..."); | |
TryAllValuesFloatVs16(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
TryAllValuesFloat(cmsOpenProfileFromFile("test0.icc", "r"), cmsOpenProfileFromFile("test0.icc", "r"), INTENT_PERCEPTUAL); | |
printf("Ok\n"); | |
} | |
// -------------------------------------------------------------------------------------------------- | |
// P E R F O R M A N C E C H E C K S | |
// -------------------------------------------------------------------------------------------------- | |
static | |
cmsFloat64Number MPixSec(cmsFloat64Number diff) | |
{ | |
cmsFloat64Number seconds = (cmsFloat64Number)diff / (cmsFloat64Number)CLOCKS_PER_SEC; | |
return (256.0 * 256.0 * 256.0) / (1024.0*1024.0*seconds); | |
} | |
typedef cmsFloat64Number(*perf_fn)(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut); | |
static | |
void PerformanceHeader(void) | |
{ | |
printf(" MPixel/sec. MByte/sec.\n"); | |
} | |
static | |
cmsFloat64Number Performance(const char* Title, perf_fn fn, cmsContext ct, const char* inICC, const char* outICC, size_t sz, cmsFloat64Number prev) | |
{ | |
cmsHPROFILE hlcmsProfileIn; | |
cmsHPROFILE hlcmsProfileOut; | |
if (inICC == NULL) | |
hlcmsProfileIn = CreateCurves(); | |
else | |
hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r"); | |
if (outICC == NULL) | |
hlcmsProfileOut = CreateCurves(); | |
else | |
hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r"); | |
cmsFloat64Number n = fn(ct, hlcmsProfileIn, hlcmsProfileOut); | |
printf("%-30s: ", Title); fflush(stdout); | |
printf("%-12.2f %-12.2f", n, n * sz); | |
if (prev > 0.0) { | |
cmsFloat64Number imp = n / prev; | |
if (imp > 1) | |
printf(" (x %-2.1f)", imp); | |
} | |
printf("\n"); fflush(stdout); | |
return n; | |
} | |
static | |
void ComparativeCt(cmsContext ct1, cmsContext ct2, const char* Title, perf_fn fn1, perf_fn fn2, const char* inICC, const char* outICC) | |
{ | |
cmsHPROFILE hlcmsProfileIn; | |
cmsHPROFILE hlcmsProfileOut; | |
if (inICC == NULL) | |
hlcmsProfileIn = CreateCurves(); | |
else | |
hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r"); | |
if (outICC == NULL) | |
hlcmsProfileOut = CreateCurves(); | |
else | |
hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r"); | |
cmsFloat64Number n1 = fn1(ct1, hlcmsProfileIn, hlcmsProfileOut); | |
if (inICC == NULL) | |
hlcmsProfileIn = CreateCurves(); | |
else | |
hlcmsProfileIn = cmsOpenProfileFromFile(inICC, "r"); | |
if (outICC == NULL) | |
hlcmsProfileOut = CreateCurves(); | |
else | |
hlcmsProfileOut = cmsOpenProfileFromFile(outICC, "r"); | |
cmsFloat64Number n2 = fn2(ct2, hlcmsProfileIn, hlcmsProfileOut); | |
printf("%-30s: ", Title); fflush(stdout); | |
printf("%-12.2f %-12.2f\n", n1, n2); | |
} | |
static | |
void Comparative(const char* Title, perf_fn fn1, perf_fn fn2, const char* inICC, const char* outICC) | |
{ | |
ComparativeCt(0, 0, Title, fn1, fn2, inICC, outICC); | |
} | |
// The worst case is used, no cache and all rgb combinations | |
static | |
cmsFloat64Number SpeedTest8bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_rgb8bits *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_8, hlcmsProfileOut, TYPE_RGB_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgb8bits); | |
In = (Scanline_rgb8bits*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsUInt8Number)r; | |
In[j].g = (cmsUInt8Number)g; | |
In[j].b = (cmsUInt8Number)b; | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
cmsFloat64Number SpeedTest8bitsRGBA(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_rgba8bits *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgba8bits); | |
In = (Scanline_rgba8bits*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsUInt8Number)r; | |
In[j].g = (cmsUInt8Number)g; | |
In[j].b = (cmsUInt8Number)b; | |
In[j].a = 0; | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
// The worst case is used, no cache and all rgb combinations | |
static | |
cmsFloat64Number SpeedTest15bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_rgb15bits *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_15, hlcmsProfileOut, TYPE_RGB_15, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgb15bits); | |
In = (Scanline_rgb15bits*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsUInt16Number)r; | |
In[j].g = (cmsUInt16Number)g; | |
In[j].b = (cmsUInt16Number)b; | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
cmsFloat64Number SpeedTest15bitsRGBA(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_rgba15bits *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_15, hlcmsProfileOut, TYPE_RGBA_15, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgba15bits); | |
In = (Scanline_rgba15bits*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsUInt16Number)r; | |
In[j].g = (cmsUInt16Number)g; | |
In[j].b = (cmsUInt16Number)b; | |
In[j].a = 0; | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
cmsFloat64Number SpeedTest15bitsCMYK(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_cmyk15bits *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_CMYK_15, hlcmsProfileOut, TYPE_CMYK_15, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_cmyk15bits); | |
In = (Scanline_cmyk15bits*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsUInt16Number)r; | |
In[j].g = (cmsUInt16Number)g; | |
In[j].b = (cmsUInt16Number)b; | |
In[j].a = (cmsUInt16Number)0; | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
// The worst case is used, no cache and all rgb combinations | |
static | |
cmsFloat64Number SpeedTest16bitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_rgb16bits *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgb16bits); | |
In = (Scanline_rgb16bits*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsUInt16Number)FROM_8_TO_16(r); | |
In[j].g = (cmsUInt16Number)FROM_8_TO_16(g); | |
In[j].b = (cmsUInt16Number)FROM_8_TO_16(b); | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
void SpeedTest8(void) | |
{ | |
cmsContext noPlugin = cmsCreateContext(0, 0); | |
cmsFloat64Number t[10]; | |
printf("\n\n"); | |
printf("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"); | |
printf("==============================================================\n\n"); | |
fflush(stdout); | |
PerformanceHeader(); | |
t[0] = Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), 0); | |
t[1] = Performance("8 bits on Matrix-Shaper ", SpeedTest8bitsRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0); | |
t[2] = Performance("8 bits on same MatrixSh ", SpeedTest8bitsRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0); | |
t[3] = Performance("8 bits on curves ", SpeedTest8bitsRGB, noPlugin, NULL, NULL, sizeof(Scanline_rgb8bits), 0); | |
// Note that context 0 has the plug-in installed | |
printf("\n\n"); | |
printf("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"); | |
printf("===========================================================\n\n"); | |
fflush(stdout); | |
PerformanceHeader(); | |
Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), t[0]); | |
Performance("8 bits on Matrix-Shaper ", SpeedTest8bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), t[1]); | |
Performance("8 bits on same MatrixSh ", SpeedTest8bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), t[2]); | |
Performance("8 bits on curves ", SpeedTest8bitsRGB, 0, NULL, NULL, sizeof(Scanline_rgb8bits), t[3]); | |
cmsDeleteContext(noPlugin); | |
} | |
#if 0 | |
static | |
void SpeedTest8(void) | |
{ | |
printf("\n\nP E R F O R M A N C E T E S T S 8 B I T S\n"); | |
printf( "==============================================\n\n"); | |
PerformanceHeader(); | |
Performance("8 bits on CLUT profiles ", SpeedTest8bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb8bits), 0); | |
Performance("8 bits on Matrix-Shaper profiles", SpeedTest8bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0); | |
Performance("8 bits on same Matrix-Shaper ", SpeedTest8bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb8bits), 0); | |
Performance("8 bits on curves ", SpeedTest8bitsRGB, 0, NULL, NULL, sizeof(Scanline_rgb8bits), 0); | |
} | |
#endif | |
static | |
void SpeedTest15(void) | |
{ | |
printf("\n\nP E R F O R M A N C E T E S T S 1 5 B I T S\n"); | |
printf( "================================================\n\n"); | |
PerformanceHeader(); | |
Performance("15 bits on CLUT profiles ", SpeedTest15bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb15bits), 0); | |
Performance("15 bits on Matrix-Shaper profiles", SpeedTest15bitsRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgb15bits), 0); | |
Performance("15 bits on same Matrix-Shaper ", SpeedTest15bitsRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgb15bits), 0); | |
Performance("15 bits on curves ", SpeedTest15bitsRGB, 0, NULL, NULL, sizeof(Scanline_rgb15bits), 0); | |
Performance("15 bits on CMYK CLUT profiles ", SpeedTest15bitsCMYK, 0, "test1.icc", "test2.icc", sizeof(Scanline_rgba15bits), 0); | |
} | |
static | |
void SpeedTest16(void) | |
{ | |
printf("\n\nP E R F O R M A N C E T E S T S 1 6 B I T S\n"); | |
printf("================================================\n\n"); | |
PerformanceHeader(); | |
Performance("16 bits on CLUT profiles ", SpeedTest16bitsRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgb15bits), 0); | |
} | |
// The worst case is used, no cache and all rgb combinations | |
static | |
cmsFloat64Number SpeedTestFloatRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
Scanline_rgbFloat *In; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGB_FLT, hlcmsProfileOut, TYPE_RGB_FLT, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
Mb = 256 * 256 * 256 * sizeof(Scanline_rgbFloat); | |
In = (Scanline_rgbFloat*)malloc(Mb); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsFloat32Number)r / 255.0f; | |
In[j].g = (cmsFloat32Number)g / 255.0f; | |
In[j].b = (cmsFloat32Number)b / 255.0f; | |
j++; | |
} | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, 256 * 256 * 256); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
void SpeedTestFloat(void) | |
{ | |
cmsContext noPlugin = cmsCreateContext(0, 0); | |
cmsFloat64Number t[10]; | |
printf("\n\n"); | |
printf("P E R F O R M A N C E T E S T S F L O A T (D E F A U L T)\n"); | |
printf("==============================================================\n\n"); | |
fflush(stdout); | |
PerformanceHeader(); | |
t[0] = Performance("Floating point on CLUT profiles ", SpeedTestFloatRGB, noPlugin, "test5.icc", "test3.icc", sizeof(Scanline_rgbFloat), 0); | |
t[1] = Performance("Floating point on Matrix-Shaper ", SpeedTestFloatRGB, noPlugin, "test5.icc", "test0.icc", sizeof(Scanline_rgbFloat), 0); | |
t[2] = Performance("Floating point on same MatrixSh ", SpeedTestFloatRGB, noPlugin, "test0.icc", "test0.icc", sizeof(Scanline_rgbFloat), 0); | |
t[3] = Performance("Floating point on curves ", SpeedTestFloatRGB, noPlugin, NULL, NULL, sizeof(Scanline_rgbFloat), 0); | |
// Note that context 0 has the plug-in installed | |
printf("\n\n"); | |
printf("P E R F O R M A N C E T E S T S F L O A T (P L U G I N)\n"); | |
printf("===========================================================\n\n"); | |
fflush(stdout); | |
PerformanceHeader(); | |
Performance("Floating point on CLUT profiles ", SpeedTestFloatRGB, 0, "test5.icc", "test3.icc", sizeof(Scanline_rgbFloat), t[0]); | |
Performance("Floating point on Matrix-Shaper ", SpeedTestFloatRGB, 0, "test5.icc", "test0.icc", sizeof(Scanline_rgbFloat), t[1]); | |
Performance("Floating point on same MatrixSh ", SpeedTestFloatRGB, 0, "test0.icc", "test0.icc", sizeof(Scanline_rgbFloat), t[2]); | |
Performance("Floating point on curves ", SpeedTestFloatRGB, 0, NULL, NULL, sizeof(Scanline_rgbFloat), t[3]); | |
cmsDeleteContext(noPlugin); | |
} | |
static | |
cmsFloat64Number SpeedTestFloatByUsing16BitsRGB(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM xform16; | |
Scanline_rgbFloat *In; | |
Scanline_rgb16bits *tmp16; | |
cmsUInt32Number MbFloat, Mb16; | |
UNUSED_PARAMETER(ct); | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
xform16 = cmsCreateTransformTHR(0, hlcmsProfileIn, TYPE_RGB_16, hlcmsProfileOut, TYPE_RGB_16, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
MbFloat = 256 * 256 * 256 * sizeof(Scanline_rgbFloat); | |
Mb16 = 256 * 256 * 256 * sizeof(Scanline_rgb16bits); | |
In = (Scanline_rgbFloat*)malloc(MbFloat); | |
tmp16 = (Scanline_rgb16bits*)malloc(Mb16); | |
j = 0; | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In[j].r = (cmsFloat32Number)r / 255.0f; | |
In[j].g = (cmsFloat32Number)g / 255.0f; | |
In[j].b = (cmsFloat32Number)b / 255.0f; | |
j++; | |
} | |
atime = clock(); | |
for (j = 0; j < 256 * 256 * 256; j++) { | |
tmp16[j].r = (cmsUInt16Number)floor(In[j].r * 65535.0 + 0.5); | |
tmp16[j].g = (cmsUInt16Number)floor(In[j].g * 65535.0 + 0.5); | |
tmp16[j].b = (cmsUInt16Number)floor(In[j].b * 65535.0 + 0.5); | |
j++; | |
} | |
cmsDoTransform(xform16, tmp16, tmp16, 256 * 256 * 256); | |
for (j = 0; j < 256 * 256 * 256; j++) { | |
In[j].r = (cmsFloat32Number) (tmp16[j].r / 65535.0 ); | |
In[j].g = (cmsFloat32Number) (tmp16[j].g / 65535.0); | |
In[j].b = (cmsFloat32Number) (tmp16[j].b / 65535.0); | |
j++; | |
} | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(xform16); | |
return MPixSec(diff); | |
} | |
static | |
void ComparativeFloatVs16bits(void) | |
{ | |
printf("\n\n"); | |
printf("C O M P A R A T I V E converting to 16 bit vs. using float plug-in.\n"); | |
printf(" values given in MegaPixels per second.\n"); | |
printf("====================================================================\n"); | |
printf(" 16 bits tmp. Float plugin\n"); | |
fflush(stdout); | |
Comparative("Floating point on CLUT profiles ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, "test5.icc", "test3.icc"); | |
Comparative("Floating point on Matrix-Shaper ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, "test5.icc", "test0.icc"); | |
Comparative("Floating point on same MatrixSh ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, "test0.icc", "test0.icc"); | |
Comparative("Floating point on curves ", SpeedTestFloatByUsing16BitsRGB, SpeedTestFloatRGB, NULL, NULL); | |
} | |
typedef struct | |
{ | |
Scanline_rgba8bits pixels[256][256]; | |
cmsUInt8Number padding[4]; | |
} padded_line; | |
typedef struct | |
{ | |
padded_line line[256]; | |
} big_bitmap; | |
static | |
cmsFloat64Number SpeedTest8bitDoTransform(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b, j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
big_bitmap* In; | |
big_bitmap* Out; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
// Our test bitmap is 256 x 256 padded lines | |
Mb = sizeof(big_bitmap); | |
In = (big_bitmap*)malloc(Mb); | |
Out = (big_bitmap*)malloc(Mb); | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In->line[r].pixels[g][b].r = (cmsUInt8Number)r; | |
In->line[r].pixels[g][b].g = (cmsUInt8Number)g; | |
In->line[r].pixels[g][b].b = (cmsUInt8Number)b; | |
In->line[r].pixels[g][b].a = 0; | |
} | |
atime = clock(); | |
for (j = 0; j < 256; j++) { | |
cmsDoTransform(hlcmsxform, In->line[j].pixels, Out->line[j].pixels, 256 * 256); | |
} | |
diff = clock() - atime; | |
free(In); free(Out); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
cmsFloat64Number SpeedTest8bitLineStride(cmsContext ct, cmsHPROFILE hlcmsProfileIn, cmsHPROFILE hlcmsProfileOut) | |
{ | |
cmsInt32Number r, g, b; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
big_bitmap* In; | |
big_bitmap* Out; | |
cmsUInt32Number Mb; | |
if (hlcmsProfileIn == NULL || hlcmsProfileOut == NULL) | |
Fail("Unable to open profiles"); | |
hlcmsxform = cmsCreateTransformTHR(ct, hlcmsProfileIn, TYPE_RGBA_8, hlcmsProfileOut, TYPE_RGBA_8, INTENT_PERCEPTUAL, cmsFLAGS_NOCACHE); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
// Our test bitmap is 256 x 256 padded lines | |
Mb = sizeof(big_bitmap); | |
In = (big_bitmap*)malloc(Mb); | |
Out = (big_bitmap*)malloc(Mb); | |
for (r = 0; r < 256; r++) | |
for (g = 0; g < 256; g++) | |
for (b = 0; b < 256; b++) { | |
In->line[r].pixels[g][b].r = (cmsUInt8Number)r; | |
In->line[r].pixels[g][b].g = (cmsUInt8Number)g; | |
In->line[r].pixels[g][b].b = (cmsUInt8Number)b; | |
In->line[r].pixels[g][b].a = 0; | |
} | |
atime = clock(); | |
cmsDoTransformLineStride(hlcmsxform, In, Out, 256*256, 256, sizeof(padded_line), sizeof(padded_line), 0, 0); | |
diff = clock() - atime; | |
free(In); free(Out); | |
cmsDeleteTransform(hlcmsxform); | |
return MPixSec(diff); | |
} | |
static | |
void ComparativeLineStride8bits(void) | |
{ | |
cmsContext NoPlugin, Plugin; | |
printf("\n\n"); | |
printf("C O M P A R A T I V E cmsDoTransform() vs. cmsDoTransformLineStride()\n"); | |
printf(" values given in MegaPixels per second.\n"); | |
printf("====================================================================\n"); | |
fflush(stdout); | |
NoPlugin = cmsCreateContext(NULL, NULL); | |
Plugin = cmsCreateContext(cmsFastFloatExtensions(), NULL); | |
ComparativeCt(NoPlugin, Plugin, "CLUT profiles ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test5.icc", "test3.icc"); | |
ComparativeCt(NoPlugin, Plugin, "CLUT 16 bits ", SpeedTest16bitsRGB, SpeedTest16bitsRGB, "test5.icc", "test3.icc"); | |
ComparativeCt(NoPlugin, Plugin, "Matrix-Shaper ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test5.icc", "test0.icc"); | |
ComparativeCt(NoPlugin, Plugin, "same MatrixSh ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, "test0.icc", "test0.icc"); | |
ComparativeCt(NoPlugin, Plugin, "curves ", SpeedTest8bitDoTransform, SpeedTest8bitLineStride, NULL, NULL); | |
cmsDeleteContext(Plugin); | |
cmsDeleteContext(NoPlugin); | |
} | |
static | |
void TestGrayTransformPerformance() | |
{ | |
cmsInt32Number j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
float *In; | |
cmsInt32Number pixels; | |
cmsUInt32Number Mb; | |
cmsToneCurve* gamma18; | |
cmsToneCurve* gamma22; | |
cmsHPROFILE hlcmsProfileIn; | |
cmsHPROFILE hlcmsProfileOut; | |
gamma18 = cmsBuildGamma(0, 1.8); | |
gamma22 = cmsBuildGamma(0, 2.2); | |
hlcmsProfileIn = cmsCreateGrayProfile(NULL, gamma18); | |
hlcmsProfileOut = cmsCreateGrayProfile(NULL, gamma22); | |
cmsFreeToneCurve(gamma18); | |
cmsFreeToneCurve(gamma22); | |
hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_GRAY_FLT | EXTRA_SH(1), hlcmsProfileOut, TYPE_GRAY_FLT|EXTRA_SH(1), INTENT_PERCEPTUAL, 0); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
pixels = 256 * 256 * 256; | |
Mb = pixels* 2*sizeof(float); | |
In = malloc(Mb); | |
for (j = 0; j < pixels*2; j++) | |
In[j] = (j % 256) / 255.0f; | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, pixels); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
printf("Gray conversion using two gray profiles\t %-12.2f MPixels/Sec.\n", MPixSec(diff)); | |
} | |
static | |
void TestGrayTransformPerformance1() | |
{ | |
cmsInt32Number j; | |
clock_t atime; | |
cmsFloat64Number diff; | |
cmsHTRANSFORM hlcmsxform; | |
float *In; | |
cmsInt32Number pixels; | |
cmsUInt32Number Mb; | |
cmsToneCurve* gamma18; | |
cmsToneCurve* gamma22; | |
cmsHPROFILE hlcmsProfileIn; | |
cmsHPROFILE hlcmsProfileOut; | |
gamma18 = cmsBuildGamma(0, 1.8); | |
gamma22 = cmsBuildGamma(0, 1./2.2); | |
hlcmsProfileIn = cmsCreateLinearizationDeviceLink(cmsSigGrayData, &gamma18); | |
hlcmsProfileOut = cmsCreateLinearizationDeviceLink(cmsSigGrayData, &gamma22); | |
cmsFreeToneCurve(gamma18); | |
cmsFreeToneCurve(gamma22); | |
hlcmsxform = cmsCreateTransform(hlcmsProfileIn, TYPE_GRAY_FLT, hlcmsProfileOut, TYPE_GRAY_FLT, INTENT_PERCEPTUAL, 0); | |
cmsCloseProfile(hlcmsProfileIn); | |
cmsCloseProfile(hlcmsProfileOut); | |
pixels = 256 * 256 * 256; | |
Mb = pixels* sizeof(float); | |
In = malloc(Mb); | |
for (j = 0; j < pixels; j++) | |
In[j] = (j % 256) / 255.0f; | |
atime = clock(); | |
cmsDoTransform(hlcmsxform, In, In, pixels); | |
diff = clock() - atime; | |
free(In); | |
cmsDeleteTransform(hlcmsxform); | |
printf("Gray conversion using two devicelinks\t %-12.2f MPixels/Sec.\n", MPixSec(diff)); | |
} | |
// The harness test | |
int main() | |
{ | |
printf("FastFloating point extensions testbed - 1.2\n"); | |
printf("Copyright (c) 1998-2020 Marti Maria Saguer, all rights reserved\n"); | |
printf("\nInstalling error logger ... "); | |
cmsSetLogErrorHandler(FatalErrorQuit); | |
printf("done.\n"); | |
printf("Installing plug-in ... "); | |
cmsPlugin(cmsFastFloatExtensions()); | |
printf("done.\n\n"); | |
CheckComputeIncrements(); | |
// 15 bit functionality | |
CheckFormatters15(); | |
Check15bitsConversions(); | |
// 16 bits functionality | |
CheckAccuracy16Bits(); | |
// Change format | |
CheckChangeFormat(); | |
// Floating point functionality | |
CheckConversionFloat(); | |
printf("All floating point tests passed OK\n"); | |
SpeedTest8(); | |
SpeedTest16(); | |
SpeedTest15(); | |
SpeedTestFloat(); | |
ComparativeFloatVs16bits(); | |
ComparativeLineStride8bits(); | |
// Test gray performance | |
printf("\n\n"); | |
printf("F L O A T G R A Y conversions performance.\n"); | |
printf("====================================================================\n"); | |
TestGrayTransformPerformance(); | |
TestGrayTransformPerformance1(); | |
printf("\nAll tests passed OK\n"); | |
return 0; | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment