src/share/native/sun/java2d/cmm/lcms/cmsopt.c
Print this page
*** 190,199 ****
--- 190,281 ----
}
return AnyOpt;
}
+
+ static
+ cmsBool CloseEnoughFloat(cmsFloat64Number a, cmsFloat64Number b)
+ {
+ return fabs(b - a) < 0.00001f;
+ }
+
+ static
+ cmsBool isFloatMatrixIdentity(const cmsMAT3* a)
+ {
+ cmsMAT3 Identity;
+ int i, j;
+
+ _cmsMAT3identity(&Identity);
+
+ for (i = 0; i < 3; i++)
+ for (j = 0; j < 3; j++)
+ if (!CloseEnoughFloat(a->v[i].n[j], Identity.v[i].n[j])) return FALSE;
+
+ return TRUE;
+ }
+ // if two adjacent matrices are found, multiply them.
+ static
+ cmsBool _MultiplyMatrix(cmsPipeline* Lut)
+ {
+ cmsStage** pt1;
+ cmsStage** pt2;
+ cmsStage* chain;
+ cmsBool AnyOpt = FALSE;
+
+ pt1 = &Lut->Elements;
+ if (*pt1 == NULL) return AnyOpt;
+
+ while (*pt1 != NULL) {
+
+ pt2 = &((*pt1)->Next);
+ if (*pt2 == NULL) return AnyOpt;
+
+ if ((*pt1)->Implements == cmsSigMatrixElemType && (*pt2)->Implements == cmsSigMatrixElemType) {
+
+ // Get both matrices
+ _cmsStageMatrixData* m1 = (_cmsStageMatrixData*) cmsStageData(*pt1);
+ _cmsStageMatrixData* m2 = (_cmsStageMatrixData*) cmsStageData(*pt2);
+ cmsMAT3 res;
+
+ // Input offset and output offset should be zero to use this optimization
+ if (m1->Offset != NULL || m2 ->Offset != NULL ||
+ cmsStageInputChannels(*pt1) != 3 || cmsStageOutputChannels(*pt1) != 3 ||
+ cmsStageInputChannels(*pt2) != 3 || cmsStageOutputChannels(*pt2) != 3)
+ return FALSE;
+
+ // Multiply both matrices to get the result
+ _cmsMAT3per(&res, (cmsMAT3*)m2->Double, (cmsMAT3*)m1->Double);
+
+ // Get the next in chain afer the matrices
+ chain = (*pt2)->Next;
+
+ // Remove both matrices
+ _RemoveElement(pt2);
+ _RemoveElement(pt1);
+
+ // Now what if the result is a plain identity?
+ if (!isFloatMatrixIdentity(&res)) {
+
+ // We can not get rid of full matrix
+ cmsStage* Multmat = cmsStageAllocMatrix(Lut->ContextID, 3, 3, (const cmsFloat64Number*) &res, NULL);
+
+ // Recover the chain
+ Multmat->Next = chain;
+ *pt1 = Multmat;
+ }
+
+ AnyOpt = TRUE;
+ }
+ else
+ pt1 = &((*pt1)->Next);
+ }
+
+ return AnyOpt;
+ }
+
+
// Preoptimize just gets rif of no-ops coming paired. Conversion from v2 to v4 followed
// by a v4 to v2 and vice-versa. The elements are then discarded.
static
cmsBool PreOptimize(cmsPipeline* Lut)
{
*** 222,231 ****
--- 304,316 ----
Opt |= _Remove2Op(Lut, cmsSigLab2FloatPCS, cmsSigFloatPCS2Lab);
// Remove float pcs Lab conversions
Opt |= _Remove2Op(Lut, cmsSigXYZ2FloatPCS, cmsSigFloatPCS2XYZ);
+ // Simplify matrix.
+ Opt |= _MultiplyMatrix(Lut);
+
if (Opt) AnyOpt = TRUE;
} while (Opt);
return AnyOpt;
*** 278,293 ****
static
void* Prelin16dup(cmsContext ContextID, const void* ptr)
{
Prelin16Data* p16 = (Prelin16Data*) ptr;
! Prelin16Data* Duped = _cmsDupMem(ContextID, p16, sizeof(Prelin16Data));
if (Duped == NULL) return NULL;
! Duped ->EvalCurveOut16 = _cmsDupMem(ContextID, p16 ->EvalCurveOut16, p16 ->nOutputs * sizeof(_cmsInterpFn16));
! Duped ->ParamsCurveOut16 = _cmsDupMem(ContextID, p16 ->ParamsCurveOut16, p16 ->nOutputs * sizeof(cmsInterpParams* ));
return Duped;
}
--- 363,378 ----
static
void* Prelin16dup(cmsContext ContextID, const void* ptr)
{
Prelin16Data* p16 = (Prelin16Data*) ptr;
! Prelin16Data* Duped = (Prelin16Data*) _cmsDupMem(ContextID, p16, sizeof(Prelin16Data));
if (Duped == NULL) return NULL;
! Duped->EvalCurveOut16 = (_cmsInterpFn16*) _cmsDupMem(ContextID, p16->EvalCurveOut16, p16->nOutputs * sizeof(_cmsInterpFn16));
! Duped->ParamsCurveOut16 = (cmsInterpParams**)_cmsDupMem(ContextID, p16->ParamsCurveOut16, p16->nOutputs * sizeof(cmsInterpParams*));
return Duped;
}
*** 296,306 ****
const cmsInterpParams* ColorMap,
int nInputs, cmsToneCurve** In,
int nOutputs, cmsToneCurve** Out )
{
int i;
! Prelin16Data* p16 = _cmsMallocZero(ContextID, sizeof(Prelin16Data));
if (p16 == NULL) return NULL;
p16 ->nInputs = nInputs;
p16 -> nOutputs = nOutputs;
--- 381,391 ----
const cmsInterpParams* ColorMap,
int nInputs, cmsToneCurve** In,
int nOutputs, cmsToneCurve** Out )
{
int i;
! Prelin16Data* p16 = (Prelin16Data*)_cmsMallocZero(ContextID, sizeof(Prelin16Data));
if (p16 == NULL) return NULL;
p16 ->nInputs = nInputs;
p16 -> nOutputs = nOutputs;
*** 785,795 ****
int i;
cmsUInt16Number Input[3];
cmsS15Fixed16Number v1, v2, v3;
Prelin8Data* p8;
! p8 = _cmsMallocZero(ContextID, sizeof(Prelin8Data));
if (p8 == NULL) return NULL;
// Since this only works for 8 bit input, values comes always as x * 257,
// we can safely take msb byte (x << 8 + x)
--- 870,880 ----
int i;
cmsUInt16Number Input[3];
cmsS15Fixed16Number v1, v2, v3;
Prelin8Data* p8;
! p8 = (Prelin8Data*)_cmsMallocZero(ContextID, sizeof(Prelin8Data));
if (p8 == NULL) return NULL;
// Since this only works for 8 bit input, values comes always as x * 257,
// we can safely take msb byte (x << 8 + x)
*** 859,869 ****
int OutChan;
register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
Prelin8Data* p8 = (Prelin8Data*) D;
register const cmsInterpParams* p = p8 ->p;
int TotalOut = p -> nOutputs;
! const cmsUInt16Number* LutTable = p -> Table;
r = Input[0] >> 8;
g = Input[1] >> 8;
b = Input[2] >> 8;
--- 944,954 ----
int OutChan;
register cmsS15Fixed16Number X0, X1, Y0, Y1, Z0, Z1;
Prelin8Data* p8 = (Prelin8Data*) D;
register const cmsInterpParams* p = p8 ->p;
int TotalOut = p -> nOutputs;
! const cmsUInt16Number* LutTable = (const cmsUInt16Number*) p->Table;
r = Input[0] >> 8;
g = Input[1] >> 8;
b = Input[2] >> 8;
*** 1178,1196 ****
}
static
void* CurvesDup(cmsContext ContextID, const void* ptr)
{
! Curves16Data* Data = _cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
int i;
if (Data == NULL) return NULL;
! Data ->Curves = _cmsDupMem(ContextID, Data ->Curves, Data ->nCurves * sizeof(cmsUInt16Number*));
for (i=0; i < Data -> nCurves; i++) {
! Data ->Curves[i] = _cmsDupMem(ContextID, Data ->Curves[i], Data -> nElements * sizeof(cmsUInt16Number));
}
return (void*) Data;
}
--- 1263,1281 ----
}
static
void* CurvesDup(cmsContext ContextID, const void* ptr)
{
! Curves16Data* Data = (Curves16Data*)_cmsDupMem(ContextID, ptr, sizeof(Curves16Data));
int i;
if (Data == NULL) return NULL;
! Data->Curves = (cmsUInt16Number**) _cmsDupMem(ContextID, Data->Curves, Data->nCurves * sizeof(cmsUInt16Number*));
for (i=0; i < Data -> nCurves; i++) {
! Data->Curves[i] = (cmsUInt16Number*) _cmsDupMem(ContextID, Data->Curves[i], Data->nElements * sizeof(cmsUInt16Number));
}
return (void*) Data;
}
*** 1199,1220 ****
Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G)
{
int i, j;
Curves16Data* c16;
! c16 = _cmsMallocZero(ContextID, sizeof(Curves16Data));
if (c16 == NULL) return NULL;
c16 ->nCurves = nCurves;
c16 ->nElements = nElements;
! c16 ->Curves = _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*));
if (c16 ->Curves == NULL) return NULL;
for (i=0; i < nCurves; i++) {
! c16->Curves[i] = _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number));
if (c16->Curves[i] == NULL) {
for (j=0; j < i; j++) {
_cmsFree(ContextID, c16->Curves[j]);
--- 1284,1305 ----
Curves16Data* CurvesAlloc(cmsContext ContextID, int nCurves, int nElements, cmsToneCurve** G)
{
int i, j;
Curves16Data* c16;
! c16 = (Curves16Data*)_cmsMallocZero(ContextID, sizeof(Curves16Data));
if (c16 == NULL) return NULL;
c16 ->nCurves = nCurves;
c16 ->nElements = nElements;
! c16->Curves = (cmsUInt16Number**) _cmsCalloc(ContextID, nCurves, sizeof(cmsUInt16Number*));
if (c16 ->Curves == NULL) return NULL;
for (i=0; i < nCurves; i++) {
! c16->Curves[i] = (cmsUInt16Number*) _cmsCalloc(ContextID, nElements, sizeof(cmsUInt16Number));
if (c16->Curves[i] == NULL) {
for (j=0; j < i; j++) {
_cmsFree(ContextID, c16->Curves[j]);
*** 1558,1622 ****
_cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper);
return TRUE;
}
// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast!
- // TODO: Allow a third matrix for abs. colorimetric
static
cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
cmsStage* Curve1, *Curve2;
cmsStage* Matrix1, *Matrix2;
- _cmsStageMatrixData* Data1;
- _cmsStageMatrixData* Data2;
cmsMAT3 res;
cmsBool IdentityMat;
cmsPipeline* Dest, *Src;
// Only works on RGB to RGB
if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE;
// Only works on 8 bit input
if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE;
// Seems suitable, proceed
Src = *Lut;
! // Check for shaper-matrix-matrix-shaper structure, that is what this optimizer stands for
! if (!cmsPipelineCheckAndRetreiveStages(Src, 4,
cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
! &Curve1, &Matrix1, &Matrix2, &Curve2)) return FALSE;
// Get both matrices
! Data1 = (_cmsStageMatrixData*) cmsStageData(Matrix1);
! Data2 = (_cmsStageMatrixData*) cmsStageData(Matrix2);
// Input offset should be zero
! if (Data1 ->Offset != NULL) return FALSE;
// Multiply both matrices to get the result
! _cmsMAT3per(&res, (cmsMAT3*) Data2 ->Double, (cmsMAT3*) Data1 ->Double);
// Now the result is in res + Data2 -> Offset. Maybe is a plain identity?
! IdentityMat = FALSE;
! if (_cmsMAT3isIdentity(&res) && Data2 ->Offset == NULL) {
// We can get rid of full matrix
IdentityMat = TRUE;
}
// Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
if (!Dest) return FALSE;
// Assamble the new LUT
if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)))
goto Error;
! if (!IdentityMat)
! if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest ->ContextID, 3, 3, (const cmsFloat64Number*) &res, Data2 ->Offset)))
goto Error;
if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)))
goto Error;
// If identity on matrix, we can further optimize the curves, so call the join curves routine
if (IdentityMat) {
--- 1643,1744 ----
_cmsPipelineSetOptimizationParameters(Dest, MatShaperEval16, (void*) p, FreeMatShaper, DupMatShaper);
return TRUE;
}
// 8 bits on input allows matrix-shaper boot up to 25 Mpixels per second on RGB. That's fast!
static
cmsBool OptimizeMatrixShaper(cmsPipeline** Lut, cmsUInt32Number Intent, cmsUInt32Number* InputFormat, cmsUInt32Number* OutputFormat, cmsUInt32Number* dwFlags)
{
cmsStage* Curve1, *Curve2;
cmsStage* Matrix1, *Matrix2;
cmsMAT3 res;
cmsBool IdentityMat;
cmsPipeline* Dest, *Src;
+ cmsFloat64Number* Offset;
// Only works on RGB to RGB
if (T_CHANNELS(*InputFormat) != 3 || T_CHANNELS(*OutputFormat) != 3) return FALSE;
// Only works on 8 bit input
if (!_cmsFormatterIs8bit(*InputFormat)) return FALSE;
// Seems suitable, proceed
Src = *Lut;
! // Check for:
! //
! // shaper-matrix-matrix-shaper
! // shaper-matrix-shaper
! //
! // Both of those constructs are possible (first because abs. colorimetric).
! // additionally, In the first case, the input matrix offset should be zero.
!
! IdentityMat = FALSE;
! if (cmsPipelineCheckAndRetreiveStages(Src, 4,
cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
! &Curve1, &Matrix1, &Matrix2, &Curve2)) {
// Get both matrices
! _cmsStageMatrixData* Data1 = (_cmsStageMatrixData*)cmsStageData(Matrix1);
! _cmsStageMatrixData* Data2 = (_cmsStageMatrixData*)cmsStageData(Matrix2);
// Input offset should be zero
! if (Data1->Offset != NULL) return FALSE;
// Multiply both matrices to get the result
! _cmsMAT3per(&res, (cmsMAT3*)Data2->Double, (cmsMAT3*)Data1->Double);
!
! // Only 2nd matrix has offset, or it is zero
! Offset = Data2->Offset;
// Now the result is in res + Data2 -> Offset. Maybe is a plain identity?
! if (_cmsMAT3isIdentity(&res) && Offset == NULL) {
!
! // We can get rid of full matrix
! IdentityMat = TRUE;
! }
!
! }
! else {
!
! if (cmsPipelineCheckAndRetreiveStages(Src, 3,
! cmsSigCurveSetElemType, cmsSigMatrixElemType, cmsSigCurveSetElemType,
! &Curve1, &Matrix1, &Curve2)) {
!
! _cmsStageMatrixData* Data = (_cmsStageMatrixData*)cmsStageData(Matrix1);
!
! // Copy the matrix to our result
! memcpy(&res, Data->Double, sizeof(res));
!
! // Preserve the Odffset (may be NULL as a zero offset)
! Offset = Data->Offset;
!
! if (_cmsMAT3isIdentity(&res) && Offset == NULL) {
// We can get rid of full matrix
IdentityMat = TRUE;
}
+ }
+ else
+ return FALSE; // Not optimizeable this time
+
+ }
// Allocate an empty LUT
Dest = cmsPipelineAlloc(Src ->ContextID, Src ->InputChannels, Src ->OutputChannels);
if (!Dest) return FALSE;
// Assamble the new LUT
if (!cmsPipelineInsertStage(Dest, cmsAT_BEGIN, cmsStageDup(Curve1)))
goto Error;
! if (!IdentityMat) {
!
! if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageAllocMatrix(Dest->ContextID, 3, 3, (const cmsFloat64Number*)&res, Offset)))
goto Error;
+ }
+
if (!cmsPipelineInsertStage(Dest, cmsAT_END, cmsStageDup(Curve2)))
goto Error;
// If identity on matrix, we can further optimize the curves, so call the join curves routine
if (IdentityMat) {
*** 1630,1640 ****
// In this particular optimization, caché does not help as it takes more time to deal with
// the caché that with the pixel handling
*dwFlags |= cmsFLAGS_NOCACHE;
// Setup the optimizarion routines
! SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Data2 ->Offset, mpeC2->TheCurves, OutputFormat);
}
cmsPipelineFree(Src);
*Lut = Dest;
return TRUE;
--- 1752,1762 ----
// In this particular optimization, caché does not help as it takes more time to deal with
// the caché that with the pixel handling
*dwFlags |= cmsFLAGS_NOCACHE;
// Setup the optimizarion routines
! SetMatShaper(Dest, mpeC1 ->TheCurves, &res, (cmsVEC3*) Offset, mpeC2->TheCurves, OutputFormat);
}
cmsPipelineFree(Src);
*Lut = Dest;
return TRUE;