1//
2// Little cms
3
4// Chameleonic header file to instantiate different versions of the
5// transform routines.
6//
7// As a bare minimum the following must be defined on entry:
8// FUNCTION_NAME the name of the function
9//
10// In addition, a range of other symbols can be optionally defined on entry
11// to make the generated code more efficient. All these symbols (and
12// FUNCTION_NAME) will be automatically undefined at the end of the file so
13// that repeated #includes of this file are made simple.
14//
15// If caching is wanted, define CACHED.
16//
17// To reduce the amount of surplus memory checking done, set INBYTES to the
18// number of bytes in an unpacked data chunk. INBYTES will only have an
19// effect if CACHED or NO_UNPACK
20//
21// If you know the code to be used to unpack (or pack, or both) data to/from
22// the simple 16 bit transform input/output format, then you can choose
23// to this directly by defining UNPACK/PACK macros as follows:
24// UNPACK(T,TO,FROM,SIZE) (Opt) code to unpack input data (T = Transform
25// TO = buffer to unpack into, FROM = data,
26// SIZE = size of data)
27// PACK(T,FROM,TO,SIZE) (Opt) code to pack transformed input data
28// (T = Transform, FROM = transformed data,
29// TO = output buffer to pack into,
30// SIZE = size of data)
31//
32// As an alternative to the above, if you know the function name that would
33// be called, supply that in UNPACKFN and PACKFN and inlining compilers
34// should hopefully do the hard work for you.
35// UNPACKFN (Opt) function to unpack input data
36// PACKFN (Opt) function to pack input data
37//
38// If the data happens to be in the correct input format anyway, we can skip
39// unpacking it entirely and just use it direct.
40// NO_UNPACK (Opt) if defined, transform direct from the input
41// data. INBYTES must be defined.
42//
43// UNPACK/PACK/UNPACKFN/PACKFN/NO_UNPACK are all expected to update their
44// TO pointer to point to the next pixels data. This means for cases where
45// we have extra bytes, they should skip the extra bytes too!
46//
47// If the data happens to be in the correct output format anyway, we can skip
48// packing it entirely and just transform it direct into the buffer.
49// NO_PACK (Opt) if defined, transform direct to the output
50// data. OUTBYTES must be defined.
51// COPY_MATCHED(FROM,TO)(Opt)if defined, copy output values from FROM to
52// TO. Used in the case CACHED case where the
53// cache matches and we have to copy forwards.
54//
55// GAMUTCHECK can be predefined if a gamut check needs to be done.
56//
57// If there are a known number of extra bytes to be dealt with, define EXTRABYTES
58// to that number (such as 0 for none).
59// If you want to provide your own code for copying from input to output, define
60// COPY_EXTRAS(TRANS,FROM,TO) to do so.
61// If none of these are defined, we call cmsHandleExtraChannels.
62
63#ifdef INBYTES
64 // Previously, we've attempted to do 'int' based checks here, but this falls
65 // foul of some compilers with their strict pointer aliasing. We have the
66 // choice of calling memcmp (which tests using chars, so is safe), or of
67 // testing using the actual type.
68 #ifdef XFORM_FLOAT
69 #if INBYTES == 4
70 #define COMPARE(A,B) ((A)[0] != (B)[0])
71 #elif INBYTES == 8
72 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]))
73 #elif INBYTES == 12
74 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]))
75 #elif INBYTES == 16
76 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3]))
77 #endif
78 #else
79 #if INBYTES == 2
80 #define COMPARE(A,B) ((A)[0] != (B)[0])
81 #elif INBYTES == 4
82 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]))
83 #elif INBYTES == 6
84 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]))
85 #elif INBYTES == 8
86 #define COMPARE(A,B) (((A)[0] != (B)[0]) || ((A)[1] != (B)[1]) || ((A)[2] != (B)[2]) || ((A)[3] != (B)[3]))
87 #endif
88 #endif
89#else
90 // Otherwise, set INBYTES to be the maximum size it could possibly be.
91 #define INBYTES (sizeof(cmsUInt16Number)*cmsMAXCHANNELS)
92#endif
93
94#ifndef COMPARE
95 #define COMPARE(A,B) memcmp((A),(B), INBYTES)
96#endif
97
98#if defined(UNPACK)
99 // Nothing to do, UNPACK is already defined
100#elif defined(NO_UNPACK)
101 #define UNPACK(CTX,T,TO,FROM,STRIDE) do { } while (0)
102#elif defined(UNPACKFN)
103 #define UNPACK(CTX,T,TO,FROM,STRIDE) \
104 do { (FROM) = UNPACKFN((CTX),(T),(TO),(FROM),(STRIDE)); } while (0)
105#elif defined(XFORM_FLOAT)
106 #define UNPACK(CTX,T,TO,FROM,STRIDE) \
107 do { (FROM) = (T)->FromInputFloat((CTX),(T),(TO),(FROM),(STRIDE)); } while (0)
108#else
109 #define UNPACK(CTX,T,TO,FROM,STRIDE) \
110 do { (FROM) = (T)->FromInput((CTX),(T),(TO),(FROM),(STRIDE)); } while (0)
111#endif
112
113#if defined(PACK)
114 // Nothing to do, PACK is already defined
115#elif defined(NO_PACK)
116 #define PACK(CTX,T,FROM,TO,STRIDE) \
117 do { (FROM) += ((OUTBYTES)/sizeof(XFORM_TYPE)); } while (0)
118#elif defined(PACKFN)
119 #define PACK(CTX,T,FROM,TO,STRIDE) \
120 do { (TO) = PACKFN((CTX),(T),(FROM),(TO),(STRIDE)); } while (0)
121#elif defined(XFORM_FLOAT)
122 #define PACK(CTX,T,FROM,TO,STRIDE) \
123 do { (TO) = (T)->ToOutputFloat((CTX),(T),(FROM),(TO),(STRIDE)); } while (0)
124#else
125 #define PACK(CTX,T,FROM,TO,STRIDE) \
126 do { (TO) = (T)->ToOutput((CTX),(T),(FROM),(TO),(STRIDE)); } while (0)
127#endif
128
129#if defined(NO_PACK) && !defined(COPY_MATCHED)
130 #if (defined(XFORM_FLOAT) && OUTBYTES == 4) || OUTBYTES == 2
131 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0])
132 #elif (defined(XFORM_FLOAT) && OUTBYTES == 8) || OUTBYTES == 4
133 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1])
134 #elif (defined(XFORM_FLOAT) && OUTBYTES == 12) || OUTBYTES == 6
135 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2])
136 #elif (defined(XFORM_FLOAT) && OUTBYTES == 16) || OUTBYTES == 8
137 #define COPY_MATCHED(FROM,TO) ((TO)[0] = (FROM)[0],(TO)[1] = (FROM)[1],(TO)[2] = (FROM)[2],(TO)[3] = (FROM)[3])
138 #else
139 #define COPY_MATCHED(FROM,TO) memcpy((TO),(FROM),(OUTBYTES))
140 #endif
141#endif
142
143#ifdef XFORM_FLOAT
144 #define XFORM_TYPE cmsFloat32Number
145#else
146 #define XFORM_TYPE cmsUInt16Number
147#endif
148
149#ifndef COPY_EXTRAS
150 #ifdef EXTRABYTES
151 #if EXTRABYTES == 0
152 #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0)
153 #else
154 #define COPY_EXTRAS(TRANS,FROM,TO) memcpy((TO),(FROM),(EXTRABYTES))
155 #endif
156 #else
157 #define BULK_COPY_EXTRAS
158 #define COPY_EXTRAS(TRANS,FROM,TO) do { } while (0)
159 #endif
160#endif
161
162static
163void FUNCTION_NAME(cmsContext ContextID,
164 _cmsTRANSFORM* p,
165 const void* in,
166 void* out,
167 cmsUInt32Number PixelsPerLine,
168 cmsUInt32Number LineCount,
169 const cmsStride* Stride)
170{
171 _cmsTRANSFORMCORE *core = p->core;
172#ifndef NO_UNPACK
173 #ifdef XFORM_FLOAT
174 cmsFloat32Number wIn[cmsMAXCHANNELS*2];
175 #else
176 cmsUInt16Number wIn[cmsMAXCHANNELS*2];
177 #endif
178 #define wIn0 (&wIn[0])
179 #define wIn1 (&wIn[cmsMAXCHANNELS])
180#endif
181 XFORM_TYPE *currIn;
182#ifdef CACHED
183 XFORM_TYPE *prevIn;
184#endif /* CACHED */
185#ifdef NO_PACK
186 XFORM_TYPE *wOut = (XFORM_TYPE *)out;
187 XFORM_TYPE *prevOut = (XFORM_TYPE *)p->Cache.CacheOut;
188#else
189 XFORM_TYPE wOut[cmsMAXCHANNELS];
190#endif
191#ifdef GAMUTCHECK
192 _cmsOPTeval16Fn evalGamut = core->GamutCheck->Eval16Fn;
193#endif /* GAMUTCHECK */
194#ifdef XFORM_FLOAT
195 _cmsPipelineEvalFloatFn eval = core->Lut->EvalFloatFn;
196 const cmsPipeline *data = core->Lut;
197#else
198 _cmsOPTeval16Fn eval = core->Lut->Eval16Fn;
199 void *data = core->Lut->Data;
200#endif
201 cmsUInt32Number bppi = Stride->BytesPerPlaneIn;
202 cmsUInt32Number bppo = Stride->BytesPerPlaneOut;
203
204 /* Silence some warnings */
205 (void)bppi;
206 (void)bppo;
207
208#ifdef BULK_COPY_EXTRAS
209 if (core->dwOriginalFlags & cmsFLAGS_COPY_ALPHA)
210 _cmsHandleExtraChannels(ContextID, p, in, out, PixelsPerLine, LineCount, Stride);
211#endif
212
213 if (PixelsPerLine == 0)
214 return;
215
216#ifdef NO_UNPACK
217 prevIn = (XFORM_TYPE *)p->Cache.CacheIn;
218#else
219 #ifdef CACHED
220 // Empty buffers for quick memcmp
221 memset(wIn1, 0, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
222
223 // Get copy of zero cache
224 memcpy(wIn0, p->Cache.CacheIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
225 memcpy(wOut, p->Cache.CacheOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
226
227 // The caller guarantees us that the cache is always valid on entry; if
228 // the representation is changed, the cache is reset.
229 prevIn = wIn0;
230 #endif /* CACHED */
231 currIn = wIn1;
232#endif
233
234 while (LineCount-- > 0)
235 {
236 cmsUInt32Number n = PixelsPerLine;
237 cmsUInt8Number* accum = (cmsUInt8Number*) in;
238 cmsUInt8Number* output = (cmsUInt8Number*) out;
239#ifdef NO_UNPACK
240 currIn = (XFORM_TYPE *)accum;
241#endif
242 while (n-- > 0) { // prevIn == CacheIn, wOut = CacheOut
243 UNPACK(ContextID,p,currIn,accum,bppi);
244#ifdef CACHED
245 if (COMPARE(currIn, prevIn))
246#endif /* CACHED */
247 {
248#ifdef GAMUTCHECK
249 #ifdef XFORM_FLOAT
250 cmsFloat32Number OutOfGamut;
251
252 // Evaluate gamut marker.
253 cmsPipelineEvalFloat(currIn, &OutOfGamut, core->GamutCheck);
254
255 // Is current color out of gamut?
256 if (OutOfGamut > 0.0)
257 // Certainly, out of gamut
258 for (j=0; j < cmsMAXCHANNELS; j++)
259 fOut[j] = -1.0;
260 else
261 #else
262 cmsUInt16Number wOutOfGamut;
263
264 evalGamut(ContextID, currIn, &wOutOfGamut, core->GamutCheck->Data);
265 if (wOutOfGamut >= 1)
266 /* RJW: Could be faster? copy once to a local buffer? */
267 cmsGetAlarmCodes(ContextID, wOut);
268 else
269 #endif /* FLOAT_XFORM */
270#endif /* GAMUTCHECK */
271 eval(ContextID, currIn, wOut, data);
272#ifdef NO_UNPACK
273 #ifdef CACHED
274 prevIn = currIn;
275 #endif
276 currIn = (XFORM_TYPE *)(((char *)currIn) + INBYTES);
277#else
278 #ifdef CACHED
279 {XFORM_TYPE *tmp = currIn; currIn = prevIn; prevIn = tmp;} // SWAP
280 #endif /* CACHED */
281#endif /* NO_UNPACK */
282 }
283#ifdef NO_PACK
284 else
285 COPY_MATCHED(prevOut,wOut);
286 prevOut = wOut;
287#endif
288 PACK(ContextID,p,wOut,output,bppo);
289 COPY_EXTRAS(p,accum,output);
290 } /* End x loop */
291 in = (void *)((cmsUInt8Number *)in + Stride->BytesPerLineIn);
292 out = (void *)((cmsUInt8Number *)out + Stride->BytesPerLineOut);
293 } /* End y loop */
294 /* The following code is only safe if we know that a given transform is
295 * called on one thread a time. */
296#if 0
297#ifdef CACHED
298#ifdef NO_UNPACK
299 memcpy(p->Cache.CacheIn,prevIn,INBYTES);
300#else
301 memcpy(p->Cache.CacheIn, prevIn, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
302#endif
303#ifdef NO_PACK
304 COPY_MATCHED(prevOut,p->Cache.CacheOut);
305#else
306 memcpy(p->Cache.CacheOut, wOut, sizeof(XFORM_TYPE) * cmsMAXCHANNELS);
307#endif /* NO_PACK */
308#endif /* CACHED */
309#endif
310}
311
312#undef wIn0
313#undef wIn1
314#undef XFORM_TYPE
315#undef XFORM_FLOAT
316
317#undef FUNCTION_NAME
318#undef COMPARE
319#undef INBYTES
320#undef OUTBYTES
321#undef UNPACK
322#undef NO_UNPACK
323#undef PACK
324#undef NO_PACK
325#undef UNPACKFN
326#undef PACKFN
327#undef GAMUTCHECK
328#undef CACHED
329#undef COPY_MATCHED
330#undef EXTRABYTES
331#undef COPY_EXTRAS
332#undef BULK_COPY_EXTRAS
333