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;