#include "fast_float_internal.h"
CMSAPI cmsBool CMSEXPORT _cmsOptimizePipeline(cmsContext ContextID,
cmsPipeline** Lut,
cmsUInt32Number Intent,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags);
typedef struct {
cmsContext ContextID;
const cmsInterpParams* p;
} Performance16Data;
static
Performance16Data* Performance16alloc(cmsContext ContextID, const cmsInterpParams* p)
{
Performance16Data* p16;
p16 = (Performance16Data*) _cmsMallocZero(ContextID, sizeof(Performance16Data));
if (p16 == NULL) return NULL;
p16 ->ContextID = ContextID;
p16 ->p = p;
return p16;
}
static
void Performance16free(cmsContext ContextID, void* ptr)
{
_cmsFree(ContextID, ptr);
}
#define TO_OUTPUT_16(d,v) do { *(cmsUInt16Number*) (d) = v; } while(0)
#define TO_OUTPUT_8(d,v) do { *(cmsUInt8Number*) (d) = FROM_16_TO_8(v); } while(0)
#define TO_OUTPUT(d,v) do { if (out16) TO_OUTPUT_16(d,v); else TO_OUTPUT_8(d,v); } while(0)
#define FROM_INPUT(v) (in16 ? (*((const cmsUInt16Number*)(v))) : FROM_8_TO_16(*((const cmsUInt8Number*)(v))))
static
void PerformanceEval16(struct _cmstransform_struct *CMMcargo,
const void* Input,
void* Output,
cmsUInt32Number PixelsPerLine,
cmsUInt32Number LineCount,
const cmsStride* Stride)
{
cmsUInt16Number r, g, b;
int x0, y0, z0;
cmsS15Fixed16Number rx, ry, rz;
cmsS15Fixed16Number fx, fy, fz;
cmsS15Fixed16Number c0, c1, c2, c3, Rest;
cmsUInt32Number OutChan, TotalPlusAlpha;
cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
Performance16Data* p16 = (Performance16Data*)_cmsGetTransformUserData(CMMcargo);
const cmsInterpParams* p = p16->p;
cmsUInt32Number TotalOut = p->nOutputs;
const cmsUInt16Number* BaseTable = (const cmsUInt16Number*)p->Table;
const cmsUInt16Number* LutTable;
cmsUInt8Number* out[cmsMAXCHANNELS];
cmsUInt16Number res16;
cmsUInt32Number i, ii;
cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];
cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];
cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];
cmsUInt32Number DestIncrements[cmsMAXCHANNELS];
const cmsUInt8Number* rin;
const cmsUInt8Number* gin;
const cmsUInt8Number* bin;
const cmsUInt8Number* ain = NULL;
int in16, out16;
cmsUInt32Number nalpha, strideIn, strideOut;
cmsUInt32Number dwInFormat = cmsGetTransformInputFormat((cmsHTRANSFORM)CMMcargo);
cmsUInt32Number dwOutFormat = cmsGetTransformOutputFormat((cmsHTRANSFORM)CMMcargo);
_cmsComputeComponentIncrements(dwInFormat, Stride->BytesPerPlaneIn, NULL, &nalpha, SourceStartingOrder, SourceIncrements);
_cmsComputeComponentIncrements(dwOutFormat, Stride->BytesPerPlaneOut, NULL, &nalpha, DestStartingOrder, DestIncrements);
in16 = (T_BYTES(dwInFormat) == 2);
out16 = (T_BYTES(dwOutFormat) == 2);
if (!(_cmsGetTransformFlags((cmsHTRANSFORM)CMMcargo) & cmsFLAGS_COPY_ALPHA))
nalpha = 0;
strideIn = strideOut = 0;
for (i = 0; i < LineCount; i++) {
rin = (const cmsUInt8Number*)Input + SourceStartingOrder[0] + strideIn;
gin = (const cmsUInt8Number*)Input + SourceStartingOrder[1] + strideIn;
bin = (const cmsUInt8Number*)Input + SourceStartingOrder[2] + strideIn;
if (nalpha)
ain = (const cmsUInt8Number*)Input + SourceStartingOrder[3] + strideIn;
TotalPlusAlpha = TotalOut;
if (ain) TotalPlusAlpha++;
for (OutChan = 0; OutChan < TotalPlusAlpha; OutChan++) {
out[OutChan] = (cmsUInt8Number*)Output + DestStartingOrder[OutChan] + strideOut;
}
for (ii = 0; ii < PixelsPerLine; ii++) {
r = FROM_INPUT(rin);
g = FROM_INPUT(gin);
b = FROM_INPUT(bin);
rin += SourceIncrements[0];
gin += SourceIncrements[1];
bin += SourceIncrements[2];
fx = _cmsToFixedDomain((int)r * p->Domain[0]);
fy = _cmsToFixedDomain((int)g * p->Domain[1]);
fz = _cmsToFixedDomain((int)b * p->Domain[2]);
x0 = FIXED_TO_INT(fx);
y0 = FIXED_TO_INT(fy);
z0 = FIXED_TO_INT(fz);
rx = FIXED_REST_TO_INT(fx);
ry = FIXED_REST_TO_INT(fy);
rz = FIXED_REST_TO_INT(fz);
X0 = p->opta[2] * x0;
X1 = (r == 0xFFFFU ? 0 : p->opta[2]);
Y0 = p->opta[1] * y0;
Y1 = (g == 0xFFFFU ? 0 : p->opta[1]);
Z0 = p->opta[0] * z0;
Z1 = (b == 0xFFFFU ? 0 : p->opta[0]);
LutTable = &BaseTable[X0 + Y0 + Z0];
if (rx >= ry) {
if (ry >= rz) {
Y1 += X1;
Z1 += Y1;
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
c1 = LutTable[X1];
c2 = LutTable[Y1];
c3 = LutTable[Z1];
c0 = *LutTable++;
c3 -= c2;
c2 -= c1;
c1 -= c0;
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
res16 = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
TO_OUTPUT(out[OutChan], res16);
out[OutChan] += DestIncrements[OutChan];
}
}
else if (rz >= rx) {
X1 += Z1;
Y1 += X1;
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
c1 = LutTable[X1];
c2 = LutTable[Y1];
c3 = LutTable[Z1];
c0 = *LutTable++;
c2 -= c1;
c1 -= c3;
c3 -= c0;
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
res16 = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
TO_OUTPUT(out[OutChan], res16);
out[OutChan] += DestIncrements[OutChan];
}
}
else {
Z1 += X1;
Y1 += Z1;
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
c1 = LutTable[X1];
c2 = LutTable[Y1];
c3 = LutTable[Z1];
c0 = *LutTable++;
c2 -= c3;
c3 -= c1;
c1 -= c0;
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
res16 = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
TO_OUTPUT(out[OutChan], res16);
out[OutChan] += DestIncrements[OutChan];
}
}
}
else {
if (rx >= rz) {
X1 += Y1;
Z1 += X1;
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
c1 = LutTable[X1];
c2 = LutTable[Y1];
c3 = LutTable[Z1];
c0 = *LutTable++;
c3 -= c1;
c1 -= c2;
c2 -= c0;
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
res16 = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
TO_OUTPUT(out[OutChan], res16);
out[OutChan] += DestIncrements[OutChan];
}
}
else if (ry >= rz) {
Z1 += Y1;
X1 += Z1;
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
c1 = LutTable[X1];
c2 = LutTable[Y1];
c3 = LutTable[Z1];
c0 = *LutTable++;
c1 -= c3;
c3 -= c2;
c2 -= c0;
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
res16 = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
TO_OUTPUT(out[OutChan], res16);
out[OutChan] += DestIncrements[OutChan];
}
}
else {
Y1 += Z1;
X1 += Y1;
for (OutChan = 0; OutChan < TotalOut; OutChan++) {
c1 = LutTable[X1];
c2 = LutTable[Y1];
c3 = LutTable[Z1];
c0 = *LutTable++;
c1 -= c2;
c2 -= c3;
c3 -= c0;
Rest = c1 * rx + c2 * ry + c3 * rz + 0x8001;
res16 = (cmsUInt16Number)c0 + ((Rest + (Rest >> 16)) >> 16);
TO_OUTPUT(out[OutChan], res16);
out[OutChan] += DestIncrements[OutChan];
}
}
}
if (ain)
{
res16 = *(const cmsUInt16Number*)ain;
TO_OUTPUT(out[TotalOut], res16);
ain += SourceIncrements[3];
out[TotalOut] += DestIncrements[TotalOut];
}
}
strideIn += Stride->BytesPerLineIn;
strideOut += Stride->BytesPerLineOut;
}
}
#undef DENS
cmsBool Optimize16BitRGBTransform(_cmsTransform2Fn* TransformFn,
void** UserData,
_cmsFreeUserDataFn* FreeDataFn,
cmsPipeline** Lut,
cmsUInt32Number* InputFormat,
cmsUInt32Number* OutputFormat,
cmsUInt32Number* dwFlags)
{
Performance16Data* p16;
cmsContext ContextID;
_cmsStageCLutData* data;
cmsUInt32Number newFlags;
cmsStage* OptimizedCLUTmpe;
if (*Lut == NULL) return FALSE;
if (T_FLOAT(*InputFormat) || T_FLOAT(*OutputFormat)) return FALSE;
if (T_BYTES(*InputFormat) != 2 || T_BYTES(*OutputFormat) != 2) return FALSE;
if (T_BIT15(*InputFormat) != 0 || T_BIT15(*OutputFormat) != 0) return FALSE;
if (T_ENDIAN16(*InputFormat) != 0 || T_ENDIAN16(*OutputFormat) != 0) return FALSE;
if (T_COLORSPACE(*InputFormat) != PT_RGB) return FALSE;
if (cmsPipelineCheckAndRetreiveStages(*Lut, 4,
cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
NULL, NULL, NULL, NULL)) return FALSE;
if (cmsPipelineCheckAndRetreiveStages(*Lut, 2,
cmsSigCurveSetElemType, cmsSigCurveSetElemType,
NULL, NULL)) return FALSE;
ContextID = cmsGetPipelineContextID(*Lut);
newFlags = *dwFlags | cmsFLAGS_FORCE_CLUT;
if (!_cmsOptimizePipeline(ContextID,
Lut,
INTENT_PERCEPTUAL, InputFormat,
OutputFormat,
&newFlags)) return FALSE;
OptimizedCLUTmpe = cmsPipelineGetPtrToFirstStage(*Lut);
data = (_cmsStageCLutData*)cmsStageData(OptimizedCLUTmpe);
p16 = Performance16alloc(ContextID, data->Params);
if (p16 == NULL) return FALSE;
*TransformFn = PerformanceEval16;
*UserData = p16;
*FreeDataFn = Performance16free;
*InputFormat |= 0x02000000;
*OutputFormat |= 0x02000000;
*dwFlags |= cmsFLAGS_CAN_CHANGE_FORMATTER;
return TRUE;
}