Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(146)

Side by Side Diff: third_party/qcms/transform.c

Issue 8079005: Remove unused qcms library. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src/
Patch Set: Created 9 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « third_party/qcms/qcmstypes.h ('k') | third_party/qcms/transform-sse1.c » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // qcms
2 // Copyright (C) 2009 Mozilla Corporation
3 // Copyright (C) 1998-2007 Marti Maria
4 //
5 // Permission is hereby granted, free of charge, to any person obtaining
6 // a copy of this software and associated documentation files (the "Software"),
7 // to deal in the Software without restriction, including without limitation
8 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
9 // and/or sell copies of the Software, and to permit persons to whom the Softwar e
10 // is furnished to do so, subject to the following conditions:
11 //
12 // The above copyright notice and this permission notice shall be included in
13 // all copies or substantial portions of the Software.
14 //
15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
17 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
19 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
20 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
21 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22
23 #include <stdlib.h>
24 #include <math.h>
25 #include <assert.h>
26 #include "qcmsint.h"
27
28 /* for MSVC, GCC, Intel, and Sun compilers */
29 #if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_AMD64 ) || defined(__x86_64__) || defined(__x86_64)
30 #define X86
31 #endif /* _M_IX86 || __i386__ || __i386 || _M_AMD64 || __x86_64__ || __x86_64 */
32
33 //XXX: could use a bettername
34 typedef uint16_t uint16_fract_t;
35
36 /* value must be a value between 0 and 1 */
37 //XXX: is the above a good restriction to have?
38 float lut_interp_linear(double value, uint16_t *table, int length)
39 {
40 int upper, lower;
41 value = value * (length - 1); // scale to length of the array
42 upper = ceil(value);
43 lower = floor(value);
44 //XXX: can we be more performant here?
45 value = table[upper]*(1. - (upper - value)) + table[lower]*(upper - valu e);
46 /* scale the value */
47 return value * (1./65535.);
48 }
49
50 /* same as above but takes and returns a uint16_t value representing a range fro m 0..1 */
51 uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
52 {
53 /* Start scaling input_value to the length of the array: 65535*(length-1 ).
54 * We'll divide out the 65535 next */
55 uint32_t value = (input_value * (length - 1));
56 uint32_t upper = (value + 65534) / 65535; /* equivalent to ceil(value/65 535) */
57 uint32_t lower = value / 65535; /* equivalent to floor(value/6 5535) */
58 /* interp is the distance from upper to value scaled to 0..65535 */
59 uint32_t interp = value % 65535;
60
61 value = (table[upper]*(interp) + table[lower]*(65535 - interp))/65535; / / 0..65535*65535
62
63 return value;
64 }
65
66 /* same as above but takes an input_value from 0..PRECACHE_OUTPUT_MAX
67 * and returns a uint8_t value representing a range from 0..1 */
68 static
69 uint8_t lut_interp_linear_precache_output(uint32_t input_value, uint16_t *table, int length)
70 {
71 /* Start scaling input_value to the length of the array: PRECACHE_OUTPUT _MAX*(length-1).
72 * We'll divide out the PRECACHE_OUTPUT_MAX next */
73 uint32_t value = (input_value * (length - 1));
74
75 /* equivalent to ceil(value/PRECACHE_OUTPUT_MAX) */
76 uint32_t upper = (value + PRECACHE_OUTPUT_MAX-1) / PRECACHE_OUTPUT_MAX;
77 /* equivalent to floor(value/PRECACHE_OUTPUT_MAX) */
78 uint32_t lower = value / PRECACHE_OUTPUT_MAX;
79 /* interp is the distance from upper to value scaled to 0..PRECACHE_OUTP UT_MAX */
80 uint32_t interp = value % PRECACHE_OUTPUT_MAX;
81
82 /* the table values range from 0..65535 */
83 value = (table[upper]*(interp) + table[lower]*(PRECACHE_OUTPUT_MAX - int erp)); // 0..(65535*PRECACHE_OUTPUT_MAX)
84
85 /* round and scale */
86 value += (PRECACHE_OUTPUT_MAX*65535/255)/2;
87 value /= (PRECACHE_OUTPUT_MAX*65535/255); // scale to 0..255
88 return value;
89 }
90
91 #if 0
92 /* if we use a different representation i.e. one that goes from 0 to 0x1000 we c an be more efficient
93 * because we can avoid the divisions and use a shifting instead */
94 /* same as above but takes and returns a uint16_t value representing a range fro m 0..1 */
95 uint16_t lut_interp_linear16(uint16_t input_value, uint16_t *table, int length)
96 {
97 uint32_t value = (input_value * (length - 1));
98 uint32_t upper = (value + 4095) / 4096; /* equivalent to ceil(value/4096 ) */
99 uint32_t lower = value / 4096; /* equivalent to floor(value/40 96) */
100 uint32_t interp = value % 4096;
101
102 value = (table[upper]*(interp) + table[lower]*(4096 - interp))/4096; // 0..4096*4096
103
104 return value;
105 }
106 #endif
107
108 void compute_curve_gamma_table_type1(float gamma_table[256], double gamma)
109 {
110 unsigned int i;
111 for (i = 0; i < 256; i++) {
112 gamma_table[i] = pow(i/255., gamma);
113 }
114 }
115
116 void compute_curve_gamma_table_type2(float gamma_table[256], uint16_t *table, in t length)
117 {
118 unsigned int i;
119 for (i = 0; i < 256; i++) {
120 gamma_table[i] = lut_interp_linear(i/255., table, length);
121 }
122 }
123
124 void compute_curve_gamma_table_type0(float gamma_table[256])
125 {
126 unsigned int i;
127 for (i = 0; i < 256; i++) {
128 gamma_table[i] = i/255.;
129 }
130 }
131
132 unsigned char clamp_u8(float v)
133 {
134 if (v > 255.)
135 return 255;
136 else if (v < 0)
137 return 0;
138 else
139 return floor(v+.5);
140 }
141
142 struct vector {
143 float v[3];
144 };
145
146 struct matrix {
147 float m[3][3];
148 bool invalid;
149 };
150
151 struct vector matrix_eval(struct matrix mat, struct vector v)
152 {
153 struct vector result;
154 result.v[0] = mat.m[0][0]*v.v[0] + mat.m[0][1]*v.v[1] + mat.m[0][2]*v.v[ 2];
155 result.v[1] = mat.m[1][0]*v.v[0] + mat.m[1][1]*v.v[1] + mat.m[1][2]*v.v[ 2];
156 result.v[2] = mat.m[2][0]*v.v[0] + mat.m[2][1]*v.v[1] + mat.m[2][2]*v.v[ 2];
157 return result;
158 }
159
160 //XXX: should probably pass by reference and we could
161 //probably reuse this computation in matrix_invert
162 float matrix_det(struct matrix mat)
163 {
164 float det;
165 det = mat.m[0][0]*mat.m[1][1]*mat.m[2][2] +
166 mat.m[0][1]*mat.m[1][2]*mat.m[2][0] +
167 mat.m[0][2]*mat.m[1][0]*mat.m[2][1] -
168 mat.m[0][0]*mat.m[1][2]*mat.m[2][1] -
169 mat.m[0][1]*mat.m[1][0]*mat.m[2][2] -
170 mat.m[0][2]*mat.m[1][1]*mat.m[2][0];
171 return det;
172 }
173
174 /* from pixman and cairo and Mathematics for Game Programmers */
175 /* lcms uses gauss-jordan elimination with partial pivoting which is
176 * less efficient and not as numerically stable. See Mathematics for
177 * Game Programmers. */
178 struct matrix matrix_invert(struct matrix mat)
179 {
180 struct matrix dest_mat;
181 int i,j;
182 static int a[3] = { 2, 2, 1 };
183 static int b[3] = { 1, 0, 0 };
184
185 /* inv (A) = 1/det (A) * adj (A) */
186 float det = matrix_det(mat);
187
188 if (det == 0) {
189 dest_mat.invalid = true;
190 } else {
191 dest_mat.invalid = false;
192 }
193
194 det = 1/det;
195
196 for (j = 0; j < 3; j++) {
197 for (i = 0; i < 3; i++) {
198 double p;
199 int ai = a[i];
200 int aj = a[j];
201 int bi = b[i];
202 int bj = b[j];
203
204 p = mat.m[ai][aj] * mat.m[bi][bj] -
205 mat.m[ai][bj] * mat.m[bi][aj];
206 if (((i + j) & 1) != 0)
207 p = -p;
208
209 dest_mat.m[j][i] = det * p;
210 }
211 }
212 return dest_mat;
213 }
214
215 struct matrix matrix_identity(void)
216 {
217 struct matrix i;
218 i.m[0][0] = 1;
219 i.m[0][1] = 0;
220 i.m[0][2] = 0;
221 i.m[1][0] = 0;
222 i.m[1][1] = 1;
223 i.m[1][2] = 0;
224 i.m[2][0] = 0;
225 i.m[2][1] = 0;
226 i.m[2][2] = 1;
227 i.invalid = false;
228 return i;
229 }
230
231 static struct matrix matrix_invalid(void)
232 {
233 struct matrix inv = matrix_identity();
234 inv.invalid = true;
235 return inv;
236 }
237
238
239 /* from pixman */
240 /* MAT3per... */
241 struct matrix matrix_multiply(struct matrix a, struct matrix b)
242 {
243 struct matrix result;
244 int dx, dy;
245 int o;
246 for (dy = 0; dy < 3; dy++) {
247 for (dx = 0; dx < 3; dx++) {
248 double v = 0;
249 for (o = 0; o < 3; o++) {
250 v += a.m[dy][o] * b.m[o][dx];
251 }
252 result.m[dy][dx] = v;
253 }
254 }
255 result.invalid = a.invalid || b.invalid;
256 return result;
257 }
258
259 float u8Fixed8Number_to_float(uint16_t x)
260 {
261 // 0x0000 = 0.
262 // 0x0100 = 1.
263 // 0xffff = 255 + 255/256
264 return x/256.;
265 }
266
267 float *build_input_gamma_table(struct curveType *TRC)
268 {
269 float *gamma_table = malloc(sizeof(float)*256);
270 if (gamma_table) {
271 if (TRC->count == 0) {
272 compute_curve_gamma_table_type0(gamma_table);
273 } else if (TRC->count == 1) {
274 compute_curve_gamma_table_type1(gamma_table, u8Fixed8Num ber_to_float(TRC->data[0]));
275 } else {
276 compute_curve_gamma_table_type2(gamma_table, TRC->data, TRC->count);
277 }
278 }
279 return gamma_table;
280 }
281
282 struct matrix build_colorant_matrix(qcms_profile *p)
283 {
284 struct matrix result;
285 result.m[0][0] = s15Fixed16Number_to_float(p->redColorant.X);
286 result.m[0][1] = s15Fixed16Number_to_float(p->greenColorant.X);
287 result.m[0][2] = s15Fixed16Number_to_float(p->blueColorant.X);
288 result.m[1][0] = s15Fixed16Number_to_float(p->redColorant.Y);
289 result.m[1][1] = s15Fixed16Number_to_float(p->greenColorant.Y);
290 result.m[1][2] = s15Fixed16Number_to_float(p->blueColorant.Y);
291 result.m[2][0] = s15Fixed16Number_to_float(p->redColorant.Z);
292 result.m[2][1] = s15Fixed16Number_to_float(p->greenColorant.Z);
293 result.m[2][2] = s15Fixed16Number_to_float(p->blueColorant.Z);
294 result.invalid = false;
295 return result;
296 }
297
298 /* The following code is copied nearly directly from lcms.
299 * I think it could be much better. For example, Argyll seems to have better cod e in
300 * icmTable_lookup_bwd and icmTable_setup_bwd. However, for now this is a quick way
301 * to a working solution and allows for easy comparing with lcms. */
302 uint16_fract_t lut_inverse_interp16(uint16_t Value, uint16_t LutTable[], int len gth)
303 {
304 int l = 1;
305 int r = 0x10000;
306 int x = 0, res; // 'int' Give spacing for negative values
307 int NumZeroes, NumPoles;
308 int cell0, cell1;
309 double val2;
310 double y0, y1, x0, x1;
311 double a, b, f;
312
313 // July/27 2001 - Expanded to handle degenerated curves with an arbitrar y
314 // number of elements containing 0 at the begining of the table (Zeroes)
315 // and another arbitrary number of poles (FFFFh) at the end.
316 // First the zero and pole extents are computed, then value is compared.
317
318 NumZeroes = 0;
319 while (LutTable[NumZeroes] == 0 && NumZeroes < length-1)
320 NumZeroes++;
321
322 // There are no zeros at the beginning and we are trying to find a zero, so
323 // return anything. It seems zero would be the less destructive choice
324 /* I'm not sure that this makes sense, but oh well... */
325 if (NumZeroes == 0 && Value == 0)
326 return 0;
327
328 NumPoles = 0;
329 while (LutTable[length-1- NumPoles] == 0xFFFF && NumPoles < length-1)
330 NumPoles++;
331
332 // Does the curve belong to this case?
333 if (NumZeroes > 1 || NumPoles > 1)
334 {
335 int a, b;
336
337 // Identify if value fall downto 0 or FFFF zone
338 if (Value == 0) return 0;
339 // if (Value == 0xFFFF) return 0xFFFF;
340
341 // else restrict to valid zone
342
343 a = ((NumZeroes-1) * 0xFFFF) / (length-1);
344 b = ((length-1 - NumPoles) * 0xFFFF) / (length-1);
345
346 l = a - 1;
347 r = b + 1;
348 }
349
350
351 // Seems not a degenerated case... apply binary search
352
353 while (r > l) {
354
355 x = (l + r) / 2;
356
357 res = (int) lut_interp_linear16((uint16_fract_t) (x-1), LutTable , length);
358
359 if (res == Value) {
360
361 // Found exact match.
362
363 return (uint16_fract_t) (x - 1);
364 }
365
366 if (res > Value) r = x - 1;
367 else l = x + 1;
368 }
369
370 // Not found, should we interpolate?
371
372
373 // Get surrounding nodes
374
375 val2 = (length-1) * ((double) (x - 1) / 65535.0);
376
377 cell0 = (int) floor(val2);
378 cell1 = (int) ceil(val2);
379
380 if (cell0 == cell1) return (uint16_fract_t) x;
381
382 y0 = LutTable[cell0] ;
383 x0 = (65535.0 * cell0) / (length-1);
384
385 y1 = LutTable[cell1] ;
386 x1 = (65535.0 * cell1) / (length-1);
387
388 a = (y1 - y0) / (x1 - x0);
389 b = y0 - a * x0;
390
391 if (fabs(a) < 0.01) return (uint16_fract_t) x;
392
393 f = ((Value - b) / a);
394
395 if (f < 0.0) return (uint16_fract_t) 0;
396 if (f >= 65535.0) return (uint16_fract_t) 0xFFFF;
397
398 return (uint16_fract_t) floor(f + 0.5);
399
400 }
401
402 // Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
403 // This is just an approximation, I am not handling all the non-linear
404 // aspects of the RGB to XYZ process, and assumming that the gamma correction
405 // has transitive property in the tranformation chain.
406 //
407 // the alghoritm:
408 //
409 // - First I build the absolute conversion matrix using
410 // primaries in XYZ. This matrix is next inverted
411 // - Then I eval the source white point across this matrix
412 // obtaining the coeficients of the transformation
413 // - Then, I apply these coeficients to the original matrix
414 static struct matrix build_RGB_to_XYZ_transfer_matrix(qcms_CIE_xyY white, qcms_C IE_xyYTRIPLE primrs)
415 {
416 struct matrix primaries;
417 struct matrix primaries_invert;
418 struct matrix result;
419 struct vector white_point;
420 struct vector coefs;
421
422 double xn, yn;
423 double xr, yr;
424 double xg, yg;
425 double xb, yb;
426
427 xn = white.x;
428 yn = white.y;
429
430 if (yn == 0.0)
431 return matrix_invalid();
432
433 xr = primrs.red.x;
434 yr = primrs.red.y;
435 xg = primrs.green.x;
436 yg = primrs.green.y;
437 xb = primrs.blue.x;
438 yb = primrs.blue.y;
439
440 primaries.m[0][0] = xr;
441 primaries.m[0][1] = xg;
442 primaries.m[0][2] = xb;
443
444 primaries.m[1][0] = yr;
445 primaries.m[1][1] = yg;
446 primaries.m[1][2] = yb;
447
448 primaries.m[2][0] = 1 - xr - yr;
449 primaries.m[2][1] = 1 - xg - yg;
450 primaries.m[2][2] = 1 - xb - yb;
451 primaries.invalid = false;
452
453 white_point.v[0] = xn/yn;
454 white_point.v[1] = 1.;
455 white_point.v[2] = (1.0-xn-yn)/yn;
456
457 primaries_invert = matrix_invert(primaries);
458
459 coefs = matrix_eval(primaries_invert, white_point);
460
461 result.m[0][0] = coefs.v[0]*xr;
462 result.m[0][1] = coefs.v[1]*xg;
463 result.m[0][2] = coefs.v[2]*xb;
464
465 result.m[1][0] = coefs.v[0]*yr;
466 result.m[1][1] = coefs.v[1]*yg;
467 result.m[1][2] = coefs.v[2]*yb;
468
469 result.m[2][0] = coefs.v[0]*(1.-xr-yr);
470 result.m[2][1] = coefs.v[1]*(1.-xg-yg);
471 result.m[2][2] = coefs.v[2]*(1.-xb-yb);
472 result.invalid = primaries_invert.invalid;
473
474 return result;
475 }
476
477 struct CIE_XYZ {
478 double X;
479 double Y;
480 double Z;
481 };
482
483 /* CIE Illuminant D50 */
484 static const struct CIE_XYZ D50_XYZ = {
485 0.9642,
486 1.0000,
487 0.8249
488 };
489
490 /* from lcms: xyY2XYZ()
491 * corresponds to argyll: icmYxy2XYZ() */
492 static struct CIE_XYZ xyY2XYZ(qcms_CIE_xyY source)
493 {
494 struct CIE_XYZ dest;
495 dest.X = (source.x / source.y) * source.Y;
496 dest.Y = source.Y;
497 dest.Z = ((1 - source.x - source.y) / source.y) * source.Y;
498 return dest;
499 }
500
501 /* from lcms: ComputeChromaticAdaption */
502 // Compute chromatic adaption matrix using chad as cone matrix
503 static struct matrix
504 compute_chromatic_adaption(struct CIE_XYZ source_white_point,
505 struct CIE_XYZ dest_white_point,
506 struct matrix chad)
507 {
508 struct matrix chad_inv;
509 struct vector cone_source_XYZ, cone_source_rgb;
510 struct vector cone_dest_XYZ, cone_dest_rgb;
511 struct matrix cone, tmp;
512
513 tmp = chad;
514 chad_inv = matrix_invert(tmp);
515
516 cone_source_XYZ.v[0] = source_white_point.X;
517 cone_source_XYZ.v[1] = source_white_point.Y;
518 cone_source_XYZ.v[2] = source_white_point.Z;
519
520 cone_dest_XYZ.v[0] = dest_white_point.X;
521 cone_dest_XYZ.v[1] = dest_white_point.Y;
522 cone_dest_XYZ.v[2] = dest_white_point.Z;
523
524 cone_source_rgb = matrix_eval(chad, cone_source_XYZ);
525 cone_dest_rgb = matrix_eval(chad, cone_dest_XYZ);
526
527 cone.m[0][0] = cone_dest_rgb.v[0]/cone_source_rgb.v[0];
528 cone.m[0][1] = 0;
529 cone.m[0][2] = 0;
530 cone.m[1][0] = 0;
531 cone.m[1][1] = cone_dest_rgb.v[1]/cone_source_rgb.v[1];
532 cone.m[1][2] = 0;
533 cone.m[2][0] = 0;
534 cone.m[2][1] = 0;
535 cone.m[2][2] = cone_dest_rgb.v[2]/cone_source_rgb.v[2];
536 cone.invalid = false;
537
538 // Normalize
539 return matrix_multiply(chad_inv, matrix_multiply(cone, chad));
540 }
541
542 /* from lcms: cmsAdaptionMatrix */
543 // Returns the final chrmatic adaptation from illuminant FromIll to Illuminant T oIll
544 // Bradford is assumed
545 static struct matrix
546 adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumi nation)
547 {
548 struct matrix lam_rigg = {{ // Bradford matrix
549 { 0.8951, 0.2664, -0.1614 },
550 { -0.7502, 1.7135, 0.0367 },
551 { 0.0389, -0.0685, 1.0296 }
552 }};
553 return compute_chromatic_adaption(source_illumination, target_illuminati on, lam_rigg);
554 }
555
556 /* from lcms: cmsAdaptMatrixToD50 */
557 static struct matrix adapt_matrix_to_D50(struct matrix r, qcms_CIE_xyY source_wh ite_pt)
558 {
559 struct CIE_XYZ Dn;
560 struct matrix Bradford;
561
562 if (source_white_pt.y == 0.0)
563 return matrix_invalid();
564
565 Dn = xyY2XYZ(source_white_pt);
566
567 Bradford = adaption_matrix(Dn, D50_XYZ);
568 return matrix_multiply(Bradford, r);
569 }
570
571 qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm s_CIE_xyYTRIPLE primaries)
572 {
573 struct matrix colorants;
574 colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
575 colorants = adapt_matrix_to_D50(colorants, white_point);
576
577 if (colorants.invalid)
578 return false;
579
580 /* note: there's a transpose type of operation going on here */
581 profile->redColorant.X = double_to_s15Fixed16Number(colorants.m[0][0]);
582 profile->redColorant.Y = double_to_s15Fixed16Number(colorants.m[1][0]);
583 profile->redColorant.Z = double_to_s15Fixed16Number(colorants.m[2][0]);
584
585 profile->greenColorant.X = double_to_s15Fixed16Number(colorants.m[0][1]) ;
586 profile->greenColorant.Y = double_to_s15Fixed16Number(colorants.m[1][1]) ;
587 profile->greenColorant.Z = double_to_s15Fixed16Number(colorants.m[2][1]) ;
588
589 profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]);
590 profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]);
591 profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]);
592
593 return true;
594 }
595
596 /*
597 The number of entries needed to invert a lookup table should not
598 necessarily be the same as the original number of entries. This is
599 especially true of lookup tables that have a small number of entries.
600
601 For example:
602 Using a table like:
603 {0, 3104, 14263, 34802, 65535}
604 invert_lut will produce an inverse of:
605 {3, 34459, 47529, 56801, 65535}
606 which has an maximum error of about 9855 (pixel difference of ~38.346)
607
608 For now, we punt the decision of output size to the caller. */
609 static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
610 {
611 int i;
612 /* for now we invert the lut by creating a lut of size out_length
613 * and attempting to lookup a value for each entry using lut_inverse_int erp16 */
614 uint16_t *output = malloc(sizeof(uint16_t)*out_length);
615 if (!output)
616 return NULL;
617
618 for (i = 0; i < out_length; i++) {
619 double x = ((double) i * 65535.) / (double) (out_length - 1);
620 uint16_fract_t input = floor(x + .5);
621 output[i] = lut_inverse_interp16(input, table, length);
622 }
623 return output;
624 }
625
626 static uint16_t *build_linear_table(int length)
627 {
628 int i;
629 uint16_t *output = malloc(sizeof(uint16_t)*length);
630 if (!output)
631 return NULL;
632
633 for (i = 0; i < length; i++) {
634 double x = ((double) i * 65535.) / (double) (length - 1);
635 uint16_fract_t input = floor(x + .5);
636 output[i] = input;
637 }
638 return output;
639 }
640
641 static uint16_t *build_pow_table(float gamma, int length)
642 {
643 int i;
644 uint16_t *output = malloc(sizeof(uint16_t)*length);
645 if (!output)
646 return NULL;
647
648 for (i = 0; i < length; i++) {
649 uint16_fract_t result;
650 double x = ((double) i) / (double) (length - 1);
651 x = pow(x, gamma);
652 //XXX turn this conversion into a function
653 result = floor(x*65535. + .5);
654 output[i] = result;
655 }
656 return output;
657 }
658
659 static float clamp_float(float a)
660 {
661 if (a > 1.)
662 return 1.;
663 else if (a < 0)
664 return 0;
665 else
666 return a;
667 }
668
669 #if 0
670 static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
671 {
672 int i;
673 float (*mat)[4] = transform->matrix;
674 for (i=0; i<length; i++) {
675 unsigned char device_r = *src++;
676 unsigned char device_g = *src++;
677 unsigned char device_b = *src++;
678
679 float linear_r = transform->input_gamma_table_r[device_r];
680 float linear_g = transform->input_gamma_table_g[device_g];
681 float linear_b = transform->input_gamma_table_b[device_b];
682
683 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
684 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
685 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
686
687 float out_device_r = pow(out_linear_r, transform->out_gamma_r);
688 float out_device_g = pow(out_linear_g, transform->out_gamma_g);
689 float out_device_b = pow(out_linear_b, transform->out_gamma_b);
690
691 *dest++ = clamp_u8(255*out_device_r);
692 *dest++ = clamp_u8(255*out_device_g);
693 *dest++ = clamp_u8(255*out_device_b);
694 }
695 }
696 #endif
697
698 static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
699 {
700 unsigned int i;
701 for (i = 0; i < length; i++) {
702 float out_device_r, out_device_g, out_device_b;
703 unsigned char device = *src++;
704
705 float linear = transform->input_gamma_table_gray[device];
706
707 out_device_r = lut_interp_linear(linear, transform->output_gamma _lut_r, transform->output_gamma_lut_r_length);
708 out_device_g = lut_interp_linear(linear, transform->output_gamma _lut_g, transform->output_gamma_lut_g_length);
709 out_device_b = lut_interp_linear(linear, transform->output_gamma _lut_b, transform->output_gamma_lut_b_length);
710
711 *dest++ = clamp_u8(out_device_r*255);
712 *dest++ = clamp_u8(out_device_g*255);
713 *dest++ = clamp_u8(out_device_b*255);
714 }
715 }
716
717 /* Alpha is not corrected.
718 A rationale for this is found in Alvy Ray's "Should Alpha Be Nonlinear If
719 RGB Is?" Tech Memo 17 (December 14, 1998).
720 See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
721 */
722
723 static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigne d char *src, unsigned char *dest, size_t length)
724 {
725 unsigned int i;
726 for (i = 0; i < length; i++) {
727 float out_device_r, out_device_g, out_device_b;
728 unsigned char device = *src++;
729 unsigned char alpha = *src++;
730
731 float linear = transform->input_gamma_table_gray[device];
732
733 out_device_r = lut_interp_linear(linear, transform->output_gamma _lut_r, transform->output_gamma_lut_r_length);
734 out_device_g = lut_interp_linear(linear, transform->output_gamma _lut_g, transform->output_gamma_lut_g_length);
735 out_device_b = lut_interp_linear(linear, transform->output_gamma _lut_b, transform->output_gamma_lut_b_length);
736
737 *dest++ = clamp_u8(out_device_r*255);
738 *dest++ = clamp_u8(out_device_g*255);
739 *dest++ = clamp_u8(out_device_b*255);
740 *dest++ = alpha;
741 }
742 }
743
744
745 static void qcms_transform_data_gray_out_precache(qcms_transform *transform, uns igned char *src, unsigned char *dest, size_t length)
746 {
747 unsigned int i;
748 for (i = 0; i < length; i++) {
749 unsigned char device = *src++;
750 uint16_t gray;
751
752 float linear = transform->input_gamma_table_gray[device];
753
754 /* we could round here... */
755 gray = linear * PRECACHE_OUTPUT_MAX;
756
757 *dest++ = transform->output_table_r->data[gray];
758 *dest++ = transform->output_table_g->data[gray];
759 *dest++ = transform->output_table_b->data[gray];
760 }
761 }
762
763 static void qcms_transform_data_graya_out_precache(qcms_transform *transform, un signed char *src, unsigned char *dest, size_t length)
764 {
765 unsigned int i;
766 for (i = 0; i < length; i++) {
767 unsigned char device = *src++;
768 unsigned char alpha = *src++;
769 uint16_t gray;
770
771 float linear = transform->input_gamma_table_gray[device];
772
773 /* we could round here... */
774 gray = linear * PRECACHE_OUTPUT_MAX;
775
776 *dest++ = transform->output_table_r->data[gray];
777 *dest++ = transform->output_table_g->data[gray];
778 *dest++ = transform->output_table_b->data[gray];
779 *dest++ = alpha;
780 }
781 }
782
783 static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
784 {
785 unsigned int i;
786 float (*mat)[4] = transform->matrix;
787 for (i = 0; i < length; i++) {
788 unsigned char device_r = *src++;
789 unsigned char device_g = *src++;
790 unsigned char device_b = *src++;
791 uint16_t r, g, b;
792
793 float linear_r = transform->input_gamma_table_r[device_r];
794 float linear_g = transform->input_gamma_table_g[device_g];
795 float linear_b = transform->input_gamma_table_b[device_b];
796
797 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
798 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
799 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
800
801 out_linear_r = clamp_float(out_linear_r);
802 out_linear_g = clamp_float(out_linear_g);
803 out_linear_b = clamp_float(out_linear_b);
804
805 /* we could round here... */
806 r = out_linear_r * PRECACHE_OUTPUT_MAX;
807 g = out_linear_g * PRECACHE_OUTPUT_MAX;
808 b = out_linear_b * PRECACHE_OUTPUT_MAX;
809
810 *dest++ = transform->output_table_r->data[r];
811 *dest++ = transform->output_table_g->data[g];
812 *dest++ = transform->output_table_b->data[b];
813 }
814 }
815
816 static void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
817 {
818 unsigned int i;
819 float (*mat)[4] = transform->matrix;
820 for (i = 0; i < length; i++) {
821 unsigned char device_r = *src++;
822 unsigned char device_g = *src++;
823 unsigned char device_b = *src++;
824 unsigned char alpha = *src++;
825 uint16_t r, g, b;
826
827 float linear_r = transform->input_gamma_table_r[device_r];
828 float linear_g = transform->input_gamma_table_g[device_g];
829 float linear_b = transform->input_gamma_table_b[device_b];
830
831 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
832 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
833 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
834
835 out_linear_r = clamp_float(out_linear_r);
836 out_linear_g = clamp_float(out_linear_g);
837 out_linear_b = clamp_float(out_linear_b);
838
839 /* we could round here... */
840 r = out_linear_r * PRECACHE_OUTPUT_MAX;
841 g = out_linear_g * PRECACHE_OUTPUT_MAX;
842 b = out_linear_b * PRECACHE_OUTPUT_MAX;
843
844 *dest++ = transform->output_table_r->data[r];
845 *dest++ = transform->output_table_g->data[g];
846 *dest++ = transform->output_table_b->data[b];
847 *dest++ = alpha;
848 }
849 }
850
851 static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
852 {
853 unsigned int i;
854 float (*mat)[4] = transform->matrix;
855 for (i = 0; i < length; i++) {
856 unsigned char device_r = *src++;
857 unsigned char device_g = *src++;
858 unsigned char device_b = *src++;
859 float out_device_r, out_device_g, out_device_b;
860
861 float linear_r = transform->input_gamma_table_r[device_r];
862 float linear_g = transform->input_gamma_table_g[device_g];
863 float linear_b = transform->input_gamma_table_b[device_b];
864
865 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
866 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
867 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
868
869 out_linear_r = clamp_float(out_linear_r);
870 out_linear_g = clamp_float(out_linear_g);
871 out_linear_b = clamp_float(out_linear_b);
872
873 out_device_r = lut_interp_linear(out_linear_r, transform->output _gamma_lut_r, transform->output_gamma_lut_r_length);
874 out_device_g = lut_interp_linear(out_linear_g, transform->output _gamma_lut_g, transform->output_gamma_lut_g_length);
875 out_device_b = lut_interp_linear(out_linear_b, transform->output _gamma_lut_b, transform->output_gamma_lut_b_length);
876
877 *dest++ = clamp_u8(out_device_r*255);
878 *dest++ = clamp_u8(out_device_g*255);
879 *dest++ = clamp_u8(out_device_b*255);
880 }
881 }
882
883 static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length)
884 {
885 unsigned int i;
886 float (*mat)[4] = transform->matrix;
887 for (i = 0; i < length; i++) {
888 unsigned char device_r = *src++;
889 unsigned char device_g = *src++;
890 unsigned char device_b = *src++;
891 unsigned char alpha = *src++;
892 float out_device_r, out_device_g, out_device_b;
893
894 float linear_r = transform->input_gamma_table_r[device_r];
895 float linear_g = transform->input_gamma_table_g[device_g];
896 float linear_b = transform->input_gamma_table_b[device_b];
897
898 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
899 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
900 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
901
902 out_linear_r = clamp_float(out_linear_r);
903 out_linear_g = clamp_float(out_linear_g);
904 out_linear_b = clamp_float(out_linear_b);
905
906 out_device_r = lut_interp_linear(out_linear_r, transform->output _gamma_lut_r, transform->output_gamma_lut_r_length);
907 out_device_g = lut_interp_linear(out_linear_g, transform->output _gamma_lut_g, transform->output_gamma_lut_g_length);
908 out_device_b = lut_interp_linear(out_linear_b, transform->output _gamma_lut_b, transform->output_gamma_lut_b_length);
909
910 *dest++ = clamp_u8(out_device_r*255);
911 *dest++ = clamp_u8(out_device_g*255);
912 *dest++ = clamp_u8(out_device_b*255);
913 *dest++ = alpha;
914 }
915 }
916
917 #if 0
918 static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsign ed char *src, unsigned char *dest, size_t length)
919 {
920 int i;
921 float (*mat)[4] = transform->matrix;
922 for (i = 0; i < length; i++) {
923 unsigned char device_r = *src++;
924 unsigned char device_g = *src++;
925 unsigned char device_b = *src++;
926
927 float linear_r = transform->input_gamma_table_r[device_r];
928 float linear_g = transform->input_gamma_table_g[device_g];
929 float linear_b = transform->input_gamma_table_b[device_b];
930
931 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
932 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
933 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
934
935 *dest++ = clamp_u8(out_linear_r*255);
936 *dest++ = clamp_u8(out_linear_g*255);
937 *dest++ = clamp_u8(out_linear_b*255);
938 }
939 }
940 #endif
941
942 static struct precache_output *precache_reference(struct precache_output *p)
943 {
944 p->ref_count++;
945 return p;
946 }
947
948 static struct precache_output *precache_create()
949 {
950 struct precache_output *p = malloc(sizeof(struct precache_output));
951 if (p)
952 p->ref_count = 1;
953 return p;
954 }
955
956 void precache_release(struct precache_output *p)
957 {
958 if (--p->ref_count == 0) {
959 free(p);
960 }
961 }
962
963 #ifdef HAS_POSIX_MEMALIGN
964 static qcms_transform *transform_alloc(void)
965 {
966 qcms_transform *t;
967 if (!posix_memalign(&t, 16, sizeof(*t))) {
968 return t;
969 } else {
970 return NULL;
971 }
972 }
973 static void transform_free(qcms_transform *t)
974 {
975 free(t);
976 }
977 #else
978 static qcms_transform *transform_alloc(void)
979 {
980 /* transform needs to be aligned on a 16byte boundrary */
981 char *original_block = calloc(sizeof(qcms_transform) + sizeof(void*) + 1 6, 1);
982 /* make room for a pointer to the block returned by calloc */
983 void *transform_start = original_block + sizeof(void*);
984 /* align transform_start */
985 qcms_transform *transform_aligned = (qcms_transform*)(((uintptr_t)transf orm_start + 15) & ~0xf);
986
987 /* store a pointer to the block returned by calloc so that we can free i t later */
988 void **(original_block_ptr) = (void**)transform_aligned;
989 if (!original_block)
990 return NULL;
991 original_block_ptr--;
992 *original_block_ptr = original_block;
993
994 return transform_aligned;
995 }
996 static void transform_free(qcms_transform *t)
997 {
998 /* get at the pointer to the unaligned block returned by calloc */
999 void **p = (void**)t;
1000 p--;
1001 free(*p);
1002 }
1003 #endif
1004
1005 void qcms_transform_release(qcms_transform *t)
1006 {
1007 /* ensure we only free the gamma tables once even if there are
1008 * multiple references to the same data */
1009
1010 if (t->output_table_r)
1011 precache_release(t->output_table_r);
1012 if (t->output_table_g)
1013 precache_release(t->output_table_g);
1014 if (t->output_table_b)
1015 precache_release(t->output_table_b);
1016
1017 free(t->input_gamma_table_r);
1018 if (t->input_gamma_table_g != t->input_gamma_table_r)
1019 free(t->input_gamma_table_g);
1020 if (t->input_gamma_table_g != t->input_gamma_table_r &&
1021 t->input_gamma_table_g != t->input_gamma_table_b)
1022 free(t->input_gamma_table_b);
1023
1024 free(t->input_gamma_table_gray);
1025
1026 free(t->output_gamma_lut_r);
1027 free(t->output_gamma_lut_g);
1028 free(t->output_gamma_lut_b);
1029
1030 transform_free(t);
1031 }
1032
1033 static void compute_precache_pow(uint8_t *output, float gamma)
1034 {
1035 uint32_t v = 0;
1036 for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) {
1037 //XXX: don't do integer/float conversion... and round?
1038 output[v] = 255. * pow(v/(double)PRECACHE_OUTPUT_MAX, gamma);
1039 }
1040 }
1041
1042 void compute_precache_lut(uint8_t *output, uint16_t *table, int length)
1043 {
1044 uint32_t v = 0;
1045 for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) {
1046 output[v] = lut_interp_linear_precache_output(v, table, length);
1047 }
1048 }
1049
1050 void compute_precache_linear(uint8_t *output)
1051 {
1052 uint32_t v = 0;
1053 for (v = 0; v < PRECACHE_OUTPUT_SIZE; v++) {
1054 //XXX: round?
1055 output[v] = v / (PRECACHE_OUTPUT_SIZE/256);
1056 }
1057 }
1058
1059 qcms_bool compute_precache(struct curveType *trc, uint8_t *output)
1060 {
1061 if (trc->count == 0) {
1062 compute_precache_linear(output);
1063 } else if (trc->count == 1) {
1064 compute_precache_pow(output, 1./u8Fixed8Number_to_float(trc->dat a[0]));
1065 } else {
1066 uint16_t *inverted;
1067 int inverted_size = trc->count;
1068 //XXX: the choice of a minimum of 256 here is not backed by any theory, measurement or data, however it is what lcms uses.
1069 // the maximum number we would need is 65535 because that's the accuracy used for computing the precache table
1070 if (inverted_size < 256)
1071 inverted_size = 256;
1072
1073 inverted = invert_lut(trc->data, trc->count, inverted_size);
1074 if (!inverted)
1075 return false;
1076 compute_precache_lut(output, inverted, inverted_size);
1077 free(inverted);
1078 }
1079 return true;
1080 }
1081
1082 #ifdef X86
1083 // Determine if we can build with SSE2 (this was partly copied from jmorecfg.h i n
1084 // mozilla/jpeg)
1085 // -------------------------------------------------------------------------
1086 #if defined(_M_IX86) && defined(_MSC_VER)
1087 #define HAS_CPUID
1088 /* Get us a CPUID function. Avoid clobbering EBX because sometimes it's the PIC
1089 register - I'm not sure if that ever happens on windows, but cpuid isn't
1090 on the critical path so we just preserve the register to be safe and to be
1091 consistent with the non-windows version. */
1092 static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
1093 uint32_t a_, b_, c_, d_;
1094 __asm {
1095 xchg ebx, esi
1096 mov eax, fxn
1097 cpuid
1098 mov a_, eax
1099 mov b_, ebx
1100 mov c_, ecx
1101 mov d_, edx
1102 xchg ebx, esi
1103 }
1104 *a = a_;
1105 *b = b_;
1106 *c = c_;
1107 *d = d_;
1108 }
1109 #elif (defined(__GNUC__) || defined(__SUNPRO_C)) && (defined(__i386__) || define d(__i386))
1110 #define HAS_CPUID
1111 /* Get us a CPUID function. We can't use ebx because it's the PIC register on
1112 some platforms, so we use ESI instead and save ebx to avoid clobbering it. */
1113 static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
1114
1115 uint32_t a_, b_, c_, d_;
1116 __asm__ __volatile__ ("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi;"
1117 : "=a" (a_), "=S" (b_), "=c" (c_), "=d" (d_) : "a" (fxn));
1118 *a = a_;
1119 *b = b_;
1120 *c = c_;
1121 *d = d_;
1122 }
1123 #endif
1124
1125 // -------------------------Runtime SSEx Detection-----------------------------
1126
1127 /* MMX is always supported per
1128 * Gecko v1.9.1 minimum CPU requirements */
1129 #define SSE1_EDX_MASK (1UL << 25)
1130 #define SSE2_EDX_MASK (1UL << 26)
1131 #define SSE3_ECX_MASK (1UL << 0)
1132
1133 static int sse_version_available(void)
1134 {
1135 #if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
1136 /* we know at build time that 64-bit CPUs always have SSE2
1137 * this tells the compiler that non-SSE2 branches will never be
1138 * taken (i.e. OK to optimze away the SSE1 and non-SIMD code */
1139 return 2;
1140 #elif defined(HAS_CPUID)
1141 static int sse_version = -1;
1142 uint32_t a, b, c, d;
1143 uint32_t function = 0x00000001;
1144
1145 if (sse_version == -1) {
1146 sse_version = 0;
1147 cpuid(function, &a, &b, &c, &d);
1148 if (c & SSE3_ECX_MASK)
1149 sse_version = 3;
1150 else if (d & SSE2_EDX_MASK)
1151 sse_version = 2;
1152 else if (d & SSE1_EDX_MASK)
1153 sse_version = 1;
1154 }
1155
1156 return sse_version;
1157 #else
1158 return 0;
1159 #endif
1160 }
1161 #endif
1162
1163 void build_output_lut(struct curveType *trc,
1164 uint16_t **output_gamma_lut, size_t *output_gamma_lut_length)
1165 {
1166 if (trc->count == 0) {
1167 *output_gamma_lut = build_linear_table(4096);
1168 *output_gamma_lut_length = 4096;
1169 } else if (trc->count == 1) {
1170 float gamma = 1./u8Fixed8Number_to_float(trc->data[0]);
1171 *output_gamma_lut = build_pow_table(gamma, 4096);
1172 *output_gamma_lut_length = 4096;
1173 } else {
1174 //XXX: the choice of a minimum of 256 here is not backed by any theory, measurement or data, however it is what lcms uses.
1175 *output_gamma_lut_length = trc->count;
1176 if (*output_gamma_lut_length < 256)
1177 *output_gamma_lut_length = 256;
1178
1179 *output_gamma_lut = invert_lut(trc->data, trc->count, *output_ga mma_lut_length);
1180 }
1181
1182 }
1183
1184 void qcms_profile_precache_output_transform(qcms_profile *profile)
1185 {
1186 /* we only support precaching on rgb profiles */
1187 if (profile->color_space != RGB_SIGNATURE)
1188 return;
1189
1190 if (!profile->output_table_r) {
1191 profile->output_table_r = precache_create();
1192 if (profile->output_table_r &&
1193 !compute_precache(profile->redTRC, profile->outp ut_table_r->data)) {
1194 precache_release(profile->output_table_r);
1195 profile->output_table_r = NULL;
1196 }
1197 }
1198 if (!profile->output_table_g) {
1199 profile->output_table_g = precache_create();
1200 if (profile->output_table_g &&
1201 !compute_precache(profile->greenTRC, profile->ou tput_table_g->data)) {
1202 precache_release(profile->output_table_g);
1203 profile->output_table_g = NULL;
1204 }
1205 }
1206 if (!profile->output_table_b) {
1207 profile->output_table_b = precache_create();
1208 if (profile->output_table_b &&
1209 !compute_precache(profile->blueTRC, profile->out put_table_b->data)) {
1210 precache_release(profile->output_table_b);
1211 profile->output_table_b = NULL;
1212 }
1213 }
1214 }
1215
1216 #define NO_MEM_TRANSFORM NULL
1217
1218 qcms_transform* qcms_transform_create(
1219 qcms_profile *in, qcms_data_type in_type,
1220 qcms_profile* out, qcms_data_type out_type,
1221 qcms_intent intent)
1222 {
1223 bool precache = false;
1224
1225 qcms_transform *transform = transform_alloc();
1226 if (!transform) {
1227 return NULL;
1228 }
1229 if (out_type != QCMS_DATA_RGB_8 &&
1230 out_type != QCMS_DATA_RGBA_8) {
1231 assert(0 && "output type");
1232 transform_free(transform);
1233 return NULL;
1234 }
1235
1236 if (out->output_table_r &&
1237 out->output_table_g &&
1238 out->output_table_b) {
1239 precache = true;
1240 }
1241
1242 if (precache) {
1243 transform->output_table_r = precache_reference(out->output_table _r);
1244 transform->output_table_g = precache_reference(out->output_table _g);
1245 transform->output_table_b = precache_reference(out->output_table _b);
1246 } else {
1247 build_output_lut(out->redTRC, &transform->output_gamma_lut_r, &t ransform->output_gamma_lut_r_length);
1248 build_output_lut(out->greenTRC, &transform->output_gamma_lut_g, &transform->output_gamma_lut_g_length);
1249 build_output_lut(out->blueTRC, &transform->output_gamma_lut_b, & transform->output_gamma_lut_b_length);
1250 if (!transform->output_gamma_lut_r || !transform->output_gamma_l ut_g || !transform->output_gamma_lut_b) {
1251 qcms_transform_release(transform);
1252 return NO_MEM_TRANSFORM;
1253 }
1254 }
1255
1256 if (in->color_space == RGB_SIGNATURE) {
1257 struct matrix in_matrix, out_matrix, result;
1258
1259 if (in_type != QCMS_DATA_RGB_8 &&
1260 in_type != QCMS_DATA_RGBA_8){
1261 assert(0 && "input type");
1262 transform_free(transform);
1263 return NULL;
1264 }
1265 if (precache) {
1266 #ifdef X86
1267 if (sse_version_available() >= 2) {
1268 if (in_type == QCMS_DATA_RGB_8)
1269 transform->transform_fn = qcms_transform_dat a_rgb_out_lut_sse2;
1270 else
1271 transform->transform_fn = qcms_transform_dat a_rgba_out_lut_sse2;
1272
1273 #if !(defined(_MSC_VER) && defined(_M_AMD64))
1274 /* Microsoft Compiler for x64 doesn't support MMX.
1275 * SSE code uses MMX so that we disable on x64 */
1276 } else
1277 if (sse_version_available() >= 1) {
1278 if (in_type == QCMS_DATA_RGB_8)
1279 transform->transform_fn = qcms_transform_dat a_rgb_out_lut_sse1;
1280 else
1281 transform->transform_fn = qcms_transform_dat a_rgba_out_lut_sse1;
1282 #endif
1283 } else
1284 #endif
1285 {
1286 if (in_type == QCMS_DATA_RGB_8)
1287 transform->transform_fn = qcms_transform_dat a_rgb_out_lut_precache;
1288 else
1289 transform->transform_fn = qcms_transform_dat a_rgba_out_lut_precache;
1290 }
1291 } else {
1292 if (in_type == QCMS_DATA_RGB_8)
1293 transform->transform_fn = qcms_transform_data_rgb_ou t_lut;
1294 else
1295 transform->transform_fn = qcms_transform_data_rgba_o ut_lut;
1296 }
1297
1298 //XXX: avoid duplicating tables if we can
1299 transform->input_gamma_table_r = build_input_gamma_table(in->redTRC) ;
1300 transform->input_gamma_table_g = build_input_gamma_table(in->greenTR C);
1301 transform->input_gamma_table_b = build_input_gamma_table(in->blueTRC );
1302
1303 if (!transform->input_gamma_table_r || !transform->input_gamma_table _g || !transform->input_gamma_table_b) {
1304 qcms_transform_release(transform);
1305 return NO_MEM_TRANSFORM;
1306 }
1307
1308 /* build combined colorant matrix */
1309 in_matrix = build_colorant_matrix(in);
1310 out_matrix = build_colorant_matrix(out);
1311 out_matrix = matrix_invert(out_matrix);
1312 if (out_matrix.invalid) {
1313 qcms_transform_release(transform);
1314 return NULL;
1315 }
1316 result = matrix_multiply(out_matrix, in_matrix);
1317
1318 /* store the results in column major mode
1319 * this makes doing the multiplication with sse easier */
1320 transform->matrix[0][0] = result.m[0][0];
1321 transform->matrix[1][0] = result.m[0][1];
1322 transform->matrix[2][0] = result.m[0][2];
1323 transform->matrix[0][1] = result.m[1][0];
1324 transform->matrix[1][1] = result.m[1][1];
1325 transform->matrix[2][1] = result.m[1][2];
1326 transform->matrix[0][2] = result.m[2][0];
1327 transform->matrix[1][2] = result.m[2][1];
1328 transform->matrix[2][2] = result.m[2][2];
1329
1330 } else if (in->color_space == GRAY_SIGNATURE) {
1331 if (in_type != QCMS_DATA_GRAY_8 &&
1332 in_type != QCMS_DATA_GRAYA_8){
1333 assert(0 && "input type");
1334 transform_free(transform);
1335 return NULL;
1336 }
1337
1338 transform->input_gamma_table_gray = build_input_gamma_table(in->gray TRC);
1339 if (!transform->input_gamma_table_gray) {
1340 qcms_transform_release(transform);
1341 return NO_MEM_TRANSFORM;
1342 }
1343
1344 if (precache) {
1345 if (in_type == QCMS_DATA_GRAY_8) {
1346 transform->transform_fn = qcms_transform_data_gray_o ut_precache;
1347 } else {
1348 transform->transform_fn = qcms_transform_data_graya_ out_precache;
1349 }
1350 } else {
1351 if (in_type == QCMS_DATA_GRAY_8) {
1352 transform->transform_fn = qcms_transform_data_gray_o ut_lut;
1353 } else {
1354 transform->transform_fn = qcms_transform_data_graya_ out_lut;
1355 }
1356 }
1357 } else {
1358 assert(0 && "unexpected colorspace");
1359 qcms_transform_release(transform);
1360 return NO_MEM_TRANSFORM;
1361 }
1362 return transform;
1363 }
1364
1365 #if defined(__GNUC__) && !defined(__x86_64__) && !defined(__amd64__)
1366 /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
1367 __attribute__((__force_align_arg_pointer__))
1368 #endif
1369 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_ t length)
1370 {
1371 transform->transform_fn(transform, src, dest, length);
1372 }
OLDNEW
« no previous file with comments | « third_party/qcms/qcmstypes.h ('k') | third_party/qcms/transform-sse1.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698