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

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

Issue 2014023003: Add exact version of qcms used by Chrome for testing and comparison (Closed) Base URL: https://skia.googlesource.com/skia.git@master
Patch Set: Created 4 years, 6 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
« no previous file with comments | « third_party/qcms/src/tests/timing.h ('k') | third_party/qcms/src/transform-sse2.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 /* vim: set ts=8 sw=8 noexpandtab: */
2 // qcms
3 // Copyright (C) 2009 Mozilla Corporation
4 // Copyright (C) 1998-2007 Marti Maria
5 //
6 // Permission is hereby granted, free of charge, to any person obtaining
7 // a copy of this software and associated documentation files (the "Software"),
8 // to deal in the Software without restriction, including without limitation
9 // the rights to use, copy, modify, merge, publish, distribute, sublicense,
10 // and/or sell copies of the Software, and to permit persons to whom the Softwar e
11 // is furnished to do so, subject to the following conditions:
12 //
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
15 //
16 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18 // THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
24 #include <stdlib.h>
25 #include <math.h>
26 #include <assert.h>
27 #include <string.h> //memcpy
28 #include "qcmsint.h"
29 #include "chain.h"
30 #include "halffloat.h"
31 #include "matrix.h"
32 #include "transform_util.h"
33
34 /* for MSVC, GCC, Intel, and Sun compilers */
35 #if defined(_M_IX86) || defined(__i386__) || defined(__i386) || defined(_M_AMD64 ) || defined(__x86_64__) || defined(__x86_64)
36 #define X86
37 #endif /* _M_IX86 || __i386__ || __i386 || _M_AMD64 || __x86_64__ || __x86_64 */
38
39 // Build a White point, primary chromas transfer matrix from RGB to CIE XYZ
40 // This is just an approximation, I am not handling all the non-linear
41 // aspects of the RGB to XYZ process, and assumming that the gamma correction
42 // has transitive property in the tranformation chain.
43 //
44 // the alghoritm:
45 //
46 // - First I build the absolute conversion matrix using
47 // primaries in XYZ. This matrix is next inverted
48 // - Then I eval the source white point across this matrix
49 // obtaining the coeficients of the transformation
50 // - Then, I apply these coeficients to the original matrix
51 static struct matrix build_RGB_to_XYZ_transfer_matrix(qcms_CIE_xyY white, qcms_C IE_xyYTRIPLE primrs)
52 {
53 struct matrix primaries;
54 struct matrix primaries_invert;
55 struct matrix result;
56 struct vector white_point;
57 struct vector coefs;
58
59 double xn, yn;
60 double xr, yr;
61 double xg, yg;
62 double xb, yb;
63
64 xn = white.x;
65 yn = white.y;
66
67 if (yn == 0.0)
68 return matrix_invalid();
69
70 xr = primrs.red.x;
71 yr = primrs.red.y;
72 xg = primrs.green.x;
73 yg = primrs.green.y;
74 xb = primrs.blue.x;
75 yb = primrs.blue.y;
76
77 primaries.m[0][0] = xr;
78 primaries.m[0][1] = xg;
79 primaries.m[0][2] = xb;
80
81 primaries.m[1][0] = yr;
82 primaries.m[1][1] = yg;
83 primaries.m[1][2] = yb;
84
85 primaries.m[2][0] = 1 - xr - yr;
86 primaries.m[2][1] = 1 - xg - yg;
87 primaries.m[2][2] = 1 - xb - yb;
88 primaries.invalid = false;
89
90 white_point.v[0] = xn/yn;
91 white_point.v[1] = 1.;
92 white_point.v[2] = (1.0-xn-yn)/yn;
93
94 primaries_invert = matrix_invert(primaries);
95
96 coefs = matrix_eval(primaries_invert, white_point);
97
98 result.m[0][0] = coefs.v[0]*xr;
99 result.m[0][1] = coefs.v[1]*xg;
100 result.m[0][2] = coefs.v[2]*xb;
101
102 result.m[1][0] = coefs.v[0]*yr;
103 result.m[1][1] = coefs.v[1]*yg;
104 result.m[1][2] = coefs.v[2]*yb;
105
106 result.m[2][0] = coefs.v[0]*(1.-xr-yr);
107 result.m[2][1] = coefs.v[1]*(1.-xg-yg);
108 result.m[2][2] = coefs.v[2]*(1.-xb-yb);
109 result.invalid = primaries_invert.invalid;
110
111 return result;
112 }
113
114 struct CIE_XYZ {
115 double X;
116 double Y;
117 double Z;
118 };
119
120 /* CIE Illuminant D50 */
121 static const struct CIE_XYZ D50_XYZ = {
122 0.9642,
123 1.0000,
124 0.8249
125 };
126
127 /* from lcms: xyY2XYZ()
128 * corresponds to argyll: icmYxy2XYZ() */
129 static struct CIE_XYZ xyY2XYZ(qcms_CIE_xyY source)
130 {
131 struct CIE_XYZ dest;
132 dest.X = (source.x / source.y) * source.Y;
133 dest.Y = source.Y;
134 dest.Z = ((1 - source.x - source.y) / source.y) * source.Y;
135 return dest;
136 }
137
138 /* from lcms: ComputeChromaticAdaption */
139 // Compute chromatic adaption matrix using chad as cone matrix
140 static struct matrix
141 compute_chromatic_adaption(struct CIE_XYZ source_white_point,
142 struct CIE_XYZ dest_white_point,
143 struct matrix chad)
144 {
145 struct matrix chad_inv;
146 struct vector cone_source_XYZ, cone_source_rgb;
147 struct vector cone_dest_XYZ, cone_dest_rgb;
148 struct matrix cone, tmp;
149
150 tmp = chad;
151 chad_inv = matrix_invert(tmp);
152
153 cone_source_XYZ.v[0] = source_white_point.X;
154 cone_source_XYZ.v[1] = source_white_point.Y;
155 cone_source_XYZ.v[2] = source_white_point.Z;
156
157 cone_dest_XYZ.v[0] = dest_white_point.X;
158 cone_dest_XYZ.v[1] = dest_white_point.Y;
159 cone_dest_XYZ.v[2] = dest_white_point.Z;
160
161 cone_source_rgb = matrix_eval(chad, cone_source_XYZ);
162 cone_dest_rgb = matrix_eval(chad, cone_dest_XYZ);
163
164 cone.m[0][0] = cone_dest_rgb.v[0]/cone_source_rgb.v[0];
165 cone.m[0][1] = 0;
166 cone.m[0][2] = 0;
167 cone.m[1][0] = 0;
168 cone.m[1][1] = cone_dest_rgb.v[1]/cone_source_rgb.v[1];
169 cone.m[1][2] = 0;
170 cone.m[2][0] = 0;
171 cone.m[2][1] = 0;
172 cone.m[2][2] = cone_dest_rgb.v[2]/cone_source_rgb.v[2];
173 cone.invalid = false;
174
175 // Normalize
176 return matrix_multiply(chad_inv, matrix_multiply(cone, chad));
177 }
178
179 /* from lcms: cmsAdaptionMatrix */
180 // Returns the final chrmatic adaptation from illuminant FromIll to Illuminant T oIll
181 // Bradford is assumed
182 static struct matrix
183 adaption_matrix(struct CIE_XYZ source_illumination, struct CIE_XYZ target_illumi nation)
184 {
185 #if defined (_MSC_VER)
186 #pragma warning(push)
187 /* Disable double to float truncation warning 4305 */
188 #pragma warning(disable:4305)
189 #endif
190 struct matrix lam_rigg = {{ // Bradford matrix
191 { 0.8951, 0.2664, -0.1614 },
192 { -0.7502, 1.7135, 0.0367 },
193 { 0.0389, -0.0685, 1.0296 }
194 }};
195 #if defined (_MSC_VER)
196 /* Restore warnings */
197 #pragma warning(pop)
198 #endif
199 return compute_chromatic_adaption(source_illumination, target_illuminati on, lam_rigg);
200 }
201
202 /* from lcms: cmsAdaptMatrixToD50 */
203 static struct matrix adapt_matrix_to_D50(struct matrix r, qcms_CIE_xyY source_wh ite_point)
204 {
205 struct CIE_XYZ DNN_XYZ;
206 struct matrix Bradford;
207
208 if (source_white_point.y == 0.0)
209 return matrix_invalid();
210
211 DNN_XYZ = xyY2XYZ(source_white_point);
212
213 Bradford = adaption_matrix(DNN_XYZ, D50_XYZ);
214
215 return matrix_multiply(Bradford, r);
216 }
217
218 qcms_bool set_rgb_colorants(qcms_profile *profile, qcms_CIE_xyY white_point, qcm s_CIE_xyYTRIPLE primaries)
219 {
220 struct CIE_XYZ source_white;
221 struct matrix colorants;
222
223 colorants = build_RGB_to_XYZ_transfer_matrix(white_point, primaries);
224 colorants = adapt_matrix_to_D50(colorants, white_point);
225
226 if (colorants.invalid)
227 return false;
228
229 /* note: there's a transpose type of operation going on here */
230 profile->redColorant.X = double_to_s15Fixed16Number(colorants.m[0][0]);
231 profile->redColorant.Y = double_to_s15Fixed16Number(colorants.m[1][0]);
232 profile->redColorant.Z = double_to_s15Fixed16Number(colorants.m[2][0]);
233
234 profile->greenColorant.X = double_to_s15Fixed16Number(colorants.m[0][1]) ;
235 profile->greenColorant.Y = double_to_s15Fixed16Number(colorants.m[1][1]) ;
236 profile->greenColorant.Z = double_to_s15Fixed16Number(colorants.m[2][1]) ;
237
238 profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]);
239 profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]);
240 profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]);
241
242 /* Store the media white point */
243 source_white = xyY2XYZ(white_point);
244 profile->mediaWhitePoint.X = double_to_s15Fixed16Number(source_white.X);
245 profile->mediaWhitePoint.Y = double_to_s15Fixed16Number(source_white.Y);
246 profile->mediaWhitePoint.Z = double_to_s15Fixed16Number(source_white.Z);
247
248 return true;
249 }
250
251 #if 0
252 static void qcms_transform_data_rgb_out_pow(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
253 {
254 const int r_out = output_format.r;
255 const int b_out = output_format.b;
256
257 int i;
258 float (*mat)[4] = transform->matrix;
259 for (i=0; i<length; i++) {
260 unsigned char device_r = *src++;
261 unsigned char device_g = *src++;
262 unsigned char device_b = *src++;
263
264 float linear_r = transform->input_gamma_table_r[device_r];
265 float linear_g = transform->input_gamma_table_g[device_g];
266 float linear_b = transform->input_gamma_table_b[device_b];
267
268 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
269 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
270 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
271
272 float out_device_r = pow(out_linear_r, transform->out_gamma_r);
273 float out_device_g = pow(out_linear_g, transform->out_gamma_g);
274 float out_device_b = pow(out_linear_b, transform->out_gamma_b);
275
276 dest[r_out] = clamp_u8(out_device_r*255);
277 dest[1] = clamp_u8(out_device_g*255);
278 dest[b_out] = clamp_u8(out_device_b*255);
279 dest += 3;
280 }
281 }
282 #endif
283
284 static void qcms_transform_data_gray_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
285 {
286 const int r_out = output_format.r;
287 const int b_out = output_format.b;
288
289 unsigned int i;
290 for (i = 0; i < length; i++) {
291 float out_device_r, out_device_g, out_device_b;
292 unsigned char device = *src++;
293
294 float linear = transform->input_gamma_table_gray[device];
295
296 out_device_r = lut_interp_linear(linear, transform->output_gamma _lut_r, transform->output_gamma_lut_r_length);
297 out_device_g = lut_interp_linear(linear, transform->output_gamma _lut_g, transform->output_gamma_lut_g_length);
298 out_device_b = lut_interp_linear(linear, transform->output_gamma _lut_b, transform->output_gamma_lut_b_length);
299
300 dest[r_out] = clamp_u8(out_device_r*255);
301 dest[1] = clamp_u8(out_device_g*255);
302 dest[b_out] = clamp_u8(out_device_b*255);
303 dest += 3;
304 }
305 }
306
307 /* Alpha is not corrected.
308 A rationale for this is found in Alvy Ray's "Should Alpha Be Nonlinear If
309 RGB Is?" Tech Memo 17 (December 14, 1998).
310 See: ftp://ftp.alvyray.com/Acrobat/17_Nonln.pdf
311 */
312
313 static void qcms_transform_data_graya_out_lut(qcms_transform *transform, unsigne d char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
314 {
315 const int r_out = output_format.r;
316 const int b_out = output_format.b;
317
318 unsigned int i;
319 for (i = 0; i < length; i++) {
320 float out_device_r, out_device_g, out_device_b;
321 unsigned char device = *src++;
322 unsigned char alpha = *src++;
323
324 float linear = transform->input_gamma_table_gray[device];
325
326 out_device_r = lut_interp_linear(linear, transform->output_gamma _lut_r, transform->output_gamma_lut_r_length);
327 out_device_g = lut_interp_linear(linear, transform->output_gamma _lut_g, transform->output_gamma_lut_g_length);
328 out_device_b = lut_interp_linear(linear, transform->output_gamma _lut_b, transform->output_gamma_lut_b_length);
329
330 dest[r_out] = clamp_u8(out_device_r*255);
331 dest[1] = clamp_u8(out_device_g*255);
332 dest[b_out] = clamp_u8(out_device_b*255);
333 dest[3] = alpha;
334 dest += 4;
335 }
336 }
337
338
339 static void qcms_transform_data_gray_out_precache(qcms_transform *transform, uns igned char *src, unsigned char *dest, size_t length, qcms_format_type output_for mat)
340 {
341 const int r_out = output_format.r;
342 const int b_out = output_format.b;
343
344 unsigned int i;
345 for (i = 0; i < length; i++) {
346 unsigned char device = *src++;
347 uint16_t gray;
348
349 float linear = transform->input_gamma_table_gray[device];
350
351 /* we could round here... */
352 gray = linear * PRECACHE_OUTPUT_MAX;
353
354 dest[r_out] = transform->output_table_r->data[gray];
355 dest[1] = transform->output_table_g->data[gray];
356 dest[b_out] = transform->output_table_b->data[gray];
357 dest += 3;
358 }
359 }
360
361
362 static void qcms_transform_data_graya_out_precache(qcms_transform *transform, un signed char *src, unsigned char *dest, size_t length, qcms_format_type output_fo rmat)
363 {
364 const int r_out = output_format.r;
365 const int b_out = output_format.b;
366
367 unsigned int i;
368 for (i = 0; i < length; i++) {
369 unsigned char device = *src++;
370 unsigned char alpha = *src++;
371 uint16_t gray;
372
373 float linear = transform->input_gamma_table_gray[device];
374
375 /* we could round here... */
376 gray = linear * PRECACHE_OUTPUT_MAX;
377
378 dest[r_out] = transform->output_table_r->data[gray];
379 dest[1] = transform->output_table_g->data[gray];
380 dest[b_out] = transform->output_table_b->data[gray];
381 dest[3] = alpha;
382 dest += 4;
383 }
384 }
385
386 static void qcms_transform_data_rgb_out_lut_precache(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_ format)
387 {
388 const int r_out = output_format.r;
389 const int b_out = output_format.b;
390
391 unsigned int i;
392 float (*mat)[4] = transform->matrix;
393 for (i = 0; i < length; i++) {
394 unsigned char device_r = *src++;
395 unsigned char device_g = *src++;
396 unsigned char device_b = *src++;
397 uint16_t r, g, b;
398
399 float linear_r = transform->input_gamma_table_r[device_r];
400 float linear_g = transform->input_gamma_table_g[device_g];
401 float linear_b = transform->input_gamma_table_b[device_b];
402
403 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
404 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
405 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
406
407 out_linear_r = clamp_float(out_linear_r);
408 out_linear_g = clamp_float(out_linear_g);
409 out_linear_b = clamp_float(out_linear_b);
410
411 /* we could round here... */
412 r = out_linear_r * PRECACHE_OUTPUT_MAX;
413 g = out_linear_g * PRECACHE_OUTPUT_MAX;
414 b = out_linear_b * PRECACHE_OUTPUT_MAX;
415
416 dest[r_out] = transform->output_table_r->data[r];
417 dest[1] = transform->output_table_g->data[g];
418 dest[b_out] = transform->output_table_b->data[b];
419 dest += 3;
420 }
421 }
422
423 void qcms_transform_data_rgba_out_lut_precache(qcms_transform *transform, unsign ed char *src, unsigned char *dest, size_t length, qcms_format_type output_format )
424 {
425 const int r_out = output_format.r;
426 const int b_out = output_format.b;
427
428 unsigned int i;
429 float (*mat)[4] = transform->matrix;
430 for (i = 0; i < length; i++) {
431 unsigned char device_r = *src++;
432 unsigned char device_g = *src++;
433 unsigned char device_b = *src++;
434 unsigned char alpha = *src++;
435 uint16_t r, g, b;
436
437 float linear_r = transform->input_gamma_table_r[device_r];
438 float linear_g = transform->input_gamma_table_g[device_g];
439 float linear_b = transform->input_gamma_table_b[device_b];
440
441 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
442 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
443 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
444
445 out_linear_r = clamp_float(out_linear_r);
446 out_linear_g = clamp_float(out_linear_g);
447 out_linear_b = clamp_float(out_linear_b);
448
449 /* we could round here... */
450 r = out_linear_r * PRECACHE_OUTPUT_MAX;
451 g = out_linear_g * PRECACHE_OUTPUT_MAX;
452 b = out_linear_b * PRECACHE_OUTPUT_MAX;
453
454 dest[r_out] = transform->output_table_r->data[r];
455 dest[1] = transform->output_table_g->data[g];
456 dest[b_out] = transform->output_table_b->data[b];
457 dest[3] = alpha;
458 dest += 4;
459 }
460 }
461
462 // Not used
463 /*
464 static void qcms_transform_data_clut(qcms_transform *transform, unsigned char *s rc, unsigned char *dest, size_t length, qcms_format_type output_format)
465 {
466 const int r_out = output_format.r;
467 const int b_out = output_format.b;
468
469 unsigned int i;
470 int xy_len = 1;
471 int x_len = transform->grid_size;
472 int len = x_len * x_len;
473 float* r_table = transform->r_clut;
474 float* g_table = transform->g_clut;
475 float* b_table = transform->b_clut;
476
477 for (i = 0; i < length; i++) {
478 unsigned char in_r = *src++;
479 unsigned char in_g = *src++;
480 unsigned char in_b = *src++;
481 float linear_r = in_r/255.0f, linear_g=in_g/255.0f, linear_b = i n_b/255.0f;
482
483 int x = floor(linear_r * (transform->grid_size-1));
484 int y = floor(linear_g * (transform->grid_size-1));
485 int z = floor(linear_b * (transform->grid_size-1));
486 int x_n = ceil(linear_r * (transform->grid_size-1));
487 int y_n = ceil(linear_g * (transform->grid_size-1));
488 int z_n = ceil(linear_b * (transform->grid_size-1));
489 float x_d = linear_r * (transform->grid_size-1) - x;
490 float y_d = linear_g * (transform->grid_size-1) - y;
491 float z_d = linear_b * (transform->grid_size-1) - z;
492
493 float r_x1 = lerp(CLU(r_table,x,y,z), CLU(r_table,x_n,y,z), x_d) ;
494 float r_x2 = lerp(CLU(r_table,x,y_n,z), CLU(r_table,x_n,y_n,z), x_d);
495 float r_y1 = lerp(r_x1, r_x2, y_d);
496 float r_x3 = lerp(CLU(r_table,x,y,z_n), CLU(r_table,x_n,y,z_n), x_d);
497 float r_x4 = lerp(CLU(r_table,x,y_n,z_n), CLU(r_table,x_n,y_n,z_ n), x_d);
498 float r_y2 = lerp(r_x3, r_x4, y_d);
499 float clut_r = lerp(r_y1, r_y2, z_d);
500
501 float g_x1 = lerp(CLU(g_table,x,y,z), CLU(g_table,x_n,y,z), x_d) ;
502 float g_x2 = lerp(CLU(g_table,x,y_n,z), CLU(g_table,x_n,y_n,z), x_d);
503 float g_y1 = lerp(g_x1, g_x2, y_d);
504 float g_x3 = lerp(CLU(g_table,x,y,z_n), CLU(g_table,x_n,y,z_n), x_d);
505 float g_x4 = lerp(CLU(g_table,x,y_n,z_n), CLU(g_table,x_n,y_n,z_ n), x_d);
506 float g_y2 = lerp(g_x3, g_x4, y_d);
507 float clut_g = lerp(g_y1, g_y2, z_d);
508
509 float b_x1 = lerp(CLU(b_table,x,y,z), CLU(b_table,x_n,y,z), x_d) ;
510 float b_x2 = lerp(CLU(b_table,x,y_n,z), CLU(b_table,x_n,y_n,z), x_d);
511 float b_y1 = lerp(b_x1, b_x2, y_d);
512 float b_x3 = lerp(CLU(b_table,x,y,z_n), CLU(b_table,x_n,y,z_n), x_d);
513 float b_x4 = lerp(CLU(b_table,x,y_n,z_n), CLU(b_table,x_n,y_n,z_ n), x_d);
514 float b_y2 = lerp(b_x3, b_x4, y_d);
515 float clut_b = lerp(b_y1, b_y2, z_d);
516
517 dest[r_out] = clamp_u8(clut_r*255.0f);
518 dest[1] = clamp_u8(clut_g*255.0f);
519 dest[b_out] = clamp_u8(clut_b*255.0f);
520 dest += 3;
521 }
522 }
523 */
524
525 // Using lcms' tetra interpolation algorithm.
526 void qcms_transform_data_tetra_clut_rgba(qcms_transform *transform, unsigned cha r *src, unsigned char *dest, size_t length, qcms_format_type output_format)
527 {
528 const int r_out = output_format.r;
529 const int b_out = output_format.b;
530
531 unsigned int i;
532 int xy_len = 1;
533 int x_len = transform->grid_size;
534 int len = x_len * x_len;
535 float* r_table = transform->r_clut;
536 float* g_table = transform->g_clut;
537 float* b_table = transform->b_clut;
538 float c0_r, c1_r, c2_r, c3_r;
539 float c0_g, c1_g, c2_g, c3_g;
540 float c0_b, c1_b, c2_b, c3_b;
541 float clut_r, clut_g, clut_b;
542
543 if (!(transform->transform_flags & TRANSFORM_FLAG_CLUT_CACHE))
544 qcms_transform_build_clut_cache(transform);
545
546 for (i = 0; i < length; i++) {
547 unsigned char in_r = *src++;
548 unsigned char in_g = *src++;
549 unsigned char in_b = *src++;
550 unsigned char in_a = *src++;
551
552 int x = transform->floor_cache[in_r];
553 int y = transform->floor_cache[in_g];
554 int z = transform->floor_cache[in_b];
555
556 int x_n = transform->ceil_cache[in_r];
557 int y_n = transform->ceil_cache[in_g];
558 int z_n = transform->ceil_cache[in_b];
559
560 float rx = transform->r_cache[in_r];
561 float ry = transform->r_cache[in_g];
562 float rz = transform->r_cache[in_b];
563
564 c0_r = CLU(r_table, x, y, z);
565 c0_g = CLU(g_table, x, y, z);
566 c0_b = CLU(b_table, x, y, z);
567
568 if( rx >= ry ) {
569 if (ry >= rz) { //rx >= ry && ry >= rz
570 c1_r = CLU(r_table, x_n, y, z) - c0_r;
571 c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
572 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table , x_n, y_n, z);
573 c1_g = CLU(g_table, x_n, y, z) - c0_g;
574 c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
575 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table , x_n, y_n, z);
576 c1_b = CLU(b_table, x_n, y, z) - c0_b;
577 c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
578 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table , x_n, y_n, z);
579 } else {
580 if (rx >= rz) { //rx >= rz && rz >= ry
581 c1_r = CLU(r_table, x_n, y, z) - c0_r;
582 c2_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y, z_n);
583 c3_r = CLU(r_table, x_n, y, z_n) - CLU(r _table, x_n, y, z);
584 c1_g = CLU(g_table, x_n, y, z) - c0_g;
585 c2_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y, z_n);
586 c3_g = CLU(g_table, x_n, y, z_n) - CLU(g _table, x_n, y, z);
587 c1_b = CLU(b_table, x_n, y, z) - c0_b;
588 c2_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y, z_n);
589 c3_b = CLU(b_table, x_n, y, z_n) - CLU(b _table, x_n, y, z);
590 } else { //rz > rx && rx >= ry
591 c1_r = CLU(r_table, x_n, y, z_n) - CLU(r _table, x, y, z_n);
592 c2_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y, z_n);
593 c3_r = CLU(r_table, x, y, z_n) - c0_r;
594 c1_g = CLU(g_table, x_n, y, z_n) - CLU(g _table, x, y, z_n);
595 c2_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y, z_n);
596 c3_g = CLU(g_table, x, y, z_n) - c0_g;
597 c1_b = CLU(b_table, x_n, y, z_n) - CLU(b _table, x, y, z_n);
598 c2_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y, z_n);
599 c3_b = CLU(b_table, x, y, z_n) - c0_b;
600 }
601 }
602 } else {
603 if (rx >= rz) { //ry > rx && rx >= rz
604 c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
605 c2_r = CLU(r_table, x, y_n, z) - c0_r;
606 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table , x_n, y_n, z);
607 c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
608 c2_g = CLU(g_table, x, y_n, z) - c0_g;
609 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table , x_n, y_n, z);
610 c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
611 c2_b = CLU(b_table, x, y_n, z) - c0_b;
612 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table , x_n, y_n, z);
613 } else {
614 if (ry >= rz) { //ry >= rz && rz > rx
615 c1_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x, y_n, z_n);
616 c2_r = CLU(r_table, x, y_n, z) - c0_r;
617 c3_r = CLU(r_table, x, y_n, z_n) - CLU(r _table, x, y_n, z);
618 c1_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x, y_n, z_n);
619 c2_g = CLU(g_table, x, y_n, z) - c0_g;
620 c3_g = CLU(g_table, x, y_n, z_n) - CLU(g _table, x, y_n, z);
621 c1_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x, y_n, z_n);
622 c2_b = CLU(b_table, x, y_n, z) - c0_b;
623 c3_b = CLU(b_table, x, y_n, z_n) - CLU(b _table, x, y_n, z);
624 } else { //rz > ry && ry > rx
625 c1_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x, y_n, z_n);
626 c2_r = CLU(r_table, x, y_n, z_n) - CLU(r _table, x, y, z_n);
627 c3_r = CLU(r_table, x, y, z_n) - c0_r;
628 c1_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x, y_n, z_n);
629 c2_g = CLU(g_table, x, y_n, z_n) - CLU(g _table, x, y, z_n);
630 c3_g = CLU(g_table, x, y, z_n) - c0_g;
631 c1_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x, y_n, z_n);
632 c2_b = CLU(b_table, x, y_n, z_n) - CLU(b _table, x, y, z_n);
633 c3_b = CLU(b_table, x, y, z_n) - c0_b;
634 }
635 }
636 }
637
638 clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
639 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
640 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
641
642 dest[r_out] = clamp_u8(clut_r*255.0f);
643 dest[1] = clamp_u8(clut_g*255.0f);
644 dest[b_out] = clamp_u8(clut_b*255.0f);
645 dest[3] = in_a;
646 dest += 4;
647 }
648 }
649
650 // Using lcms' tetra interpolation code.
651 static void qcms_transform_data_tetra_clut(qcms_transform *transform, unsigned c har *src, unsigned char *dest, size_t length, qcms_format_type output_format)
652 {
653 const int r_out = output_format.r;
654 const int b_out = output_format.b;
655
656 unsigned int i;
657 int xy_len = 1;
658 int x_len = transform->grid_size;
659 int len = x_len * x_len;
660 float* r_table = transform->r_clut;
661 float* g_table = transform->g_clut;
662 float* b_table = transform->b_clut;
663 float c0_r, c1_r, c2_r, c3_r;
664 float c0_g, c1_g, c2_g, c3_g;
665 float c0_b, c1_b, c2_b, c3_b;
666 float clut_r, clut_g, clut_b;
667
668 if (!(transform->transform_flags & TRANSFORM_FLAG_CLUT_CACHE))
669 qcms_transform_build_clut_cache(transform);
670
671 for (i = 0; i < length; i++) {
672 unsigned char in_r = *src++;
673 unsigned char in_g = *src++;
674 unsigned char in_b = *src++;
675
676 int x = transform->floor_cache[in_r];
677 int y = transform->floor_cache[in_g];
678 int z = transform->floor_cache[in_b];
679
680 int x_n = transform->ceil_cache[in_r];
681 int y_n = transform->ceil_cache[in_g];
682 int z_n = transform->ceil_cache[in_b];
683
684 float rx = transform->r_cache[in_r];
685 float ry = transform->r_cache[in_g];
686 float rz = transform->r_cache[in_b];
687
688 c0_r = CLU(r_table, x, y, z);
689 c0_g = CLU(g_table, x, y, z);
690 c0_b = CLU(b_table, x, y, z);
691
692 if( rx >= ry ) {
693 if (ry >= rz) { //rx >= ry && ry >= rz
694 c1_r = CLU(r_table, x_n, y, z) - c0_r;
695 c2_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x_n, y, z);
696 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table , x_n, y_n, z);
697 c1_g = CLU(g_table, x_n, y, z) - c0_g;
698 c2_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x_n, y, z);
699 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table , x_n, y_n, z);
700 c1_b = CLU(b_table, x_n, y, z) - c0_b;
701 c2_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x_n, y, z);
702 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table , x_n, y_n, z);
703 } else {
704 if (rx >= rz) { //rx >= rz && rz >= ry
705 c1_r = CLU(r_table, x_n, y, z) - c0_r;
706 c2_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y, z_n);
707 c3_r = CLU(r_table, x_n, y, z_n) - CLU(r _table, x_n, y, z);
708 c1_g = CLU(g_table, x_n, y, z) - c0_g;
709 c2_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y, z_n);
710 c3_g = CLU(g_table, x_n, y, z_n) - CLU(g _table, x_n, y, z);
711 c1_b = CLU(b_table, x_n, y, z) - c0_b;
712 c2_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y, z_n);
713 c3_b = CLU(b_table, x_n, y, z_n) - CLU(b _table, x_n, y, z);
714 } else { //rz > rx && rx >= ry
715 c1_r = CLU(r_table, x_n, y, z_n) - CLU(r _table, x, y, z_n);
716 c2_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x_n, y, z_n);
717 c3_r = CLU(r_table, x, y, z_n) - c0_r;
718 c1_g = CLU(g_table, x_n, y, z_n) - CLU(g _table, x, y, z_n);
719 c2_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x_n, y, z_n);
720 c3_g = CLU(g_table, x, y, z_n) - c0_g;
721 c1_b = CLU(b_table, x_n, y, z_n) - CLU(b _table, x, y, z_n);
722 c2_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x_n, y, z_n);
723 c3_b = CLU(b_table, x, y, z_n) - c0_b;
724 }
725 }
726 } else {
727 if (rx >= rz) { //ry > rx && rx >= rz
728 c1_r = CLU(r_table, x_n, y_n, z) - CLU(r_table, x, y_n, z);
729 c2_r = CLU(r_table, x, y_n, z) - c0_r;
730 c3_r = CLU(r_table, x_n, y_n, z_n) - CLU(r_table , x_n, y_n, z);
731 c1_g = CLU(g_table, x_n, y_n, z) - CLU(g_table, x, y_n, z);
732 c2_g = CLU(g_table, x, y_n, z) - c0_g;
733 c3_g = CLU(g_table, x_n, y_n, z_n) - CLU(g_table , x_n, y_n, z);
734 c1_b = CLU(b_table, x_n, y_n, z) - CLU(b_table, x, y_n, z);
735 c2_b = CLU(b_table, x, y_n, z) - c0_b;
736 c3_b = CLU(b_table, x_n, y_n, z_n) - CLU(b_table , x_n, y_n, z);
737 } else {
738 if (ry >= rz) { //ry >= rz && rz > rx
739 c1_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x, y_n, z_n);
740 c2_r = CLU(r_table, x, y_n, z) - c0_r;
741 c3_r = CLU(r_table, x, y_n, z_n) - CLU(r _table, x, y_n, z);
742 c1_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x, y_n, z_n);
743 c2_g = CLU(g_table, x, y_n, z) - c0_g;
744 c3_g = CLU(g_table, x, y_n, z_n) - CLU(g _table, x, y_n, z);
745 c1_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x, y_n, z_n);
746 c2_b = CLU(b_table, x, y_n, z) - c0_b;
747 c3_b = CLU(b_table, x, y_n, z_n) - CLU(b _table, x, y_n, z);
748 } else { //rz > ry && ry > rx
749 c1_r = CLU(r_table, x_n, y_n, z_n) - CLU (r_table, x, y_n, z_n);
750 c2_r = CLU(r_table, x, y_n, z_n) - CLU(r _table, x, y, z_n);
751 c3_r = CLU(r_table, x, y, z_n) - c0_r;
752 c1_g = CLU(g_table, x_n, y_n, z_n) - CLU (g_table, x, y_n, z_n);
753 c2_g = CLU(g_table, x, y_n, z_n) - CLU(g _table, x, y, z_n);
754 c3_g = CLU(g_table, x, y, z_n) - c0_g;
755 c1_b = CLU(b_table, x_n, y_n, z_n) - CLU (b_table, x, y_n, z_n);
756 c2_b = CLU(b_table, x, y_n, z_n) - CLU(b _table, x, y, z_n);
757 c3_b = CLU(b_table, x, y, z_n) - c0_b;
758 }
759 }
760 }
761
762 clut_r = c0_r + c1_r*rx + c2_r*ry + c3_r*rz;
763 clut_g = c0_g + c1_g*rx + c2_g*ry + c3_g*rz;
764 clut_b = c0_b + c1_b*rx + c2_b*ry + c3_b*rz;
765
766 dest[r_out] = clamp_u8(clut_r*255.0f);
767 dest[1] = clamp_u8(clut_g*255.0f);
768 dest[b_out] = clamp_u8(clut_b*255.0f);
769 dest += 3;
770 }
771 }
772
773 static void qcms_transform_data_rgb_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
774 {
775 const int r_out = output_format.r;
776 const int b_out = output_format.b;
777
778 unsigned int i;
779 float (*mat)[4] = transform->matrix;
780 for (i = 0; i < length; i++) {
781 unsigned char device_r = *src++;
782 unsigned char device_g = *src++;
783 unsigned char device_b = *src++;
784 float out_device_r, out_device_g, out_device_b;
785
786 float linear_r = transform->input_gamma_table_r[device_r];
787 float linear_g = transform->input_gamma_table_g[device_g];
788 float linear_b = transform->input_gamma_table_b[device_b];
789
790 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
791 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
792 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
793
794 out_linear_r = clamp_float(out_linear_r);
795 out_linear_g = clamp_float(out_linear_g);
796 out_linear_b = clamp_float(out_linear_b);
797
798 out_device_r = lut_interp_linear(out_linear_r,
799 transform->output_gamma_lut_r, transform->output _gamma_lut_r_length);
800 out_device_g = lut_interp_linear(out_linear_g,
801 transform->output_gamma_lut_g, transform->output _gamma_lut_g_length);
802 out_device_b = lut_interp_linear(out_linear_b,
803 transform->output_gamma_lut_b, transform->output _gamma_lut_b_length);
804
805 dest[r_out] = clamp_u8(out_device_r*255);
806 dest[1] = clamp_u8(out_device_g*255);
807 dest[b_out] = clamp_u8(out_device_b*255);
808 dest += 3;
809 }
810 }
811
812 static void qcms_transform_data_rgba_out_lut(qcms_transform *transform, unsigned char *src, unsigned char *dest, size_t length, qcms_format_type output_format)
813 {
814 const int r_out = output_format.r;
815 const int b_out = output_format.b;
816
817 unsigned int i;
818 float (*mat)[4] = transform->matrix;
819 for (i = 0; i < length; i++) {
820 unsigned char device_r = *src++;
821 unsigned char device_g = *src++;
822 unsigned char device_b = *src++;
823 unsigned char alpha = *src++;
824 float out_device_r, out_device_g, out_device_b;
825
826 float linear_r = transform->input_gamma_table_r[device_r];
827 float linear_g = transform->input_gamma_table_g[device_g];
828 float linear_b = transform->input_gamma_table_b[device_b];
829
830 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
831 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
832 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
833
834 out_linear_r = clamp_float(out_linear_r);
835 out_linear_g = clamp_float(out_linear_g);
836 out_linear_b = clamp_float(out_linear_b);
837
838 out_device_r = lut_interp_linear(out_linear_r,
839 transform->output_gamma_lut_r, transform->output _gamma_lut_r_length);
840 out_device_g = lut_interp_linear(out_linear_g,
841 transform->output_gamma_lut_g, transform->output _gamma_lut_g_length);
842 out_device_b = lut_interp_linear(out_linear_b,
843 transform->output_gamma_lut_b, transform->output _gamma_lut_b_length);
844
845 dest[r_out] = clamp_u8(out_device_r*255);
846 dest[1] = clamp_u8(out_device_g*255);
847 dest[b_out] = clamp_u8(out_device_b*255);
848 dest[3] = alpha;
849 dest += 4;
850 }
851 }
852
853 #if 0
854 static void qcms_transform_data_rgb_out_linear(qcms_transform *transform, unsign ed char *src, unsigned char *dest, size_t length, qcms_format_type output_format )
855 {
856 const int r_out = output_format.r;
857 const int b_out = output_format.b;
858
859 int i;
860 float (*mat)[4] = transform->matrix;
861 for (i = 0; i < length; i++) {
862 unsigned char device_r = *src++;
863 unsigned char device_g = *src++;
864 unsigned char device_b = *src++;
865
866 float linear_r = transform->input_gamma_table_r[device_r];
867 float linear_g = transform->input_gamma_table_g[device_g];
868 float linear_b = transform->input_gamma_table_b[device_b];
869
870 float out_linear_r = mat[0][0]*linear_r + mat[1][0]*linear_g + m at[2][0]*linear_b;
871 float out_linear_g = mat[0][1]*linear_r + mat[1][1]*linear_g + m at[2][1]*linear_b;
872 float out_linear_b = mat[0][2]*linear_r + mat[1][2]*linear_g + m at[2][2]*linear_b;
873
874 dest[r_out] = clamp_u8(out_linear_r*255);
875 dest[1] = clamp_u8(out_linear_g*255);
876 dest[b_out] = clamp_u8(out_linear_b*255);
877 dest += 3;
878 }
879 }
880 #endif
881
882 /*
883 * If users create and destroy objects on different threads, even if the same
884 * objects aren't used on different threads at the same time, we can still run
885 * in to trouble with refcounts if they aren't atomic.
886 *
887 * This can lead to us prematurely deleting the precache if threads get unlucky
888 * and write the wrong value to the ref count.
889 */
890 static struct precache_output *precache_reference(struct precache_output *p)
891 {
892 qcms_atomic_increment(p->ref_count);
893 return p;
894 }
895
896 static struct precache_output *precache_create()
897 {
898 struct precache_output *p = malloc(sizeof(struct precache_output));
899 if (p)
900 p->ref_count = 1;
901 return p;
902 }
903
904 void precache_release(struct precache_output *p)
905 {
906 if (qcms_atomic_decrement(p->ref_count) == 0) {
907 free(p);
908 }
909 }
910
911 #ifdef HAVE_POSIX_MEMALIGN
912 static qcms_transform *transform_alloc(void)
913 {
914 qcms_transform *t;
915 if (!posix_memalign(&t, 16, sizeof(*t))) {
916 return t;
917 } else {
918 return NULL;
919 }
920 }
921 static void transform_free(qcms_transform *t)
922 {
923 free(t);
924 }
925 #else
926 static qcms_transform *transform_alloc(void)
927 {
928 /* transform needs to be aligned on a 16byte boundrary */
929 char *original_block = calloc(sizeof(qcms_transform) + sizeof(void*) + 1 6, 1);
930 /* make room for a pointer to the block returned by calloc */
931 void *transform_start = original_block + sizeof(void*);
932 /* align transform_start */
933 qcms_transform *transform_aligned = (qcms_transform*)(((uintptr_t)transf orm_start + 15) & ~0xf);
934
935 /* store a pointer to the block returned by calloc so that we can free i t later */
936 void **(original_block_ptr) = (void**)transform_aligned;
937 if (!original_block)
938 return NULL;
939 original_block_ptr--;
940 *original_block_ptr = original_block;
941
942 return transform_aligned;
943 }
944 static void transform_free(qcms_transform *t)
945 {
946 /* get at the pointer to the unaligned block returned by calloc */
947 void **p = (void**)t;
948 p--;
949 free(*p);
950 }
951 #endif
952
953 void qcms_transform_release(qcms_transform *t)
954 {
955 /* ensure we only free the gamma tables once even if there are
956 * multiple references to the same data */
957
958 if (t->output_table_r)
959 precache_release(t->output_table_r);
960 if (t->output_table_g)
961 precache_release(t->output_table_g);
962 if (t->output_table_b)
963 precache_release(t->output_table_b);
964
965 free(t->input_gamma_table_r);
966 if (t->input_gamma_table_g != t->input_gamma_table_r)
967 free(t->input_gamma_table_g);
968 if (t->input_gamma_table_g != t->input_gamma_table_r &&
969 t->input_gamma_table_g != t->input_gamma_table_b)
970 free(t->input_gamma_table_b);
971
972 free(t->input_gamma_table_gray);
973
974 free(t->output_gamma_lut_r);
975 free(t->output_gamma_lut_g);
976 free(t->output_gamma_lut_b);
977
978 transform_free(t);
979 }
980
981 #ifdef X86
982 // Determine if we can build with SSE2 (this was partly copied from jmorecfg.h i n
983 // mozilla/jpeg)
984 // -------------------------------------------------------------------------
985 #if defined(_M_IX86) && defined(_MSC_VER)
986 #define HAS_CPUID
987 /* Get us a CPUID function. Avoid clobbering EBX because sometimes it's the PIC
988 register - I'm not sure if that ever happens on windows, but cpuid isn't
989 on the critical path so we just preserve the register to be safe and to be
990 consistent with the non-windows version. */
991 static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
992 uint32_t a_, b_, c_, d_;
993 __asm {
994 xchg ebx, esi
995 mov eax, fxn
996 cpuid
997 mov a_, eax
998 mov b_, ebx
999 mov c_, ecx
1000 mov d_, edx
1001 xchg ebx, esi
1002 }
1003 *a = a_;
1004 *b = b_;
1005 *c = c_;
1006 *d = d_;
1007 }
1008 #elif (defined(__GNUC__) || defined(__SUNPRO_C)) && (defined(__i386__) || define d(__i386))
1009 #define HAS_CPUID
1010 /* Get us a CPUID function. We can't use ebx because it's the PIC register on
1011 some platforms, so we use ESI instead and save ebx to avoid clobbering it. */
1012 static void cpuid(uint32_t fxn, uint32_t *a, uint32_t *b, uint32_t *c, uint32_t *d) {
1013
1014 uint32_t a_, b_, c_, d_;
1015 __asm__ __volatile__ ("xchgl %%ebx, %%esi; cpuid; xchgl %%ebx, %%esi;"
1016 : "=a" (a_), "=S" (b_), "=c" (c_), "=d" (d_) : "a" (fxn));
1017 *a = a_;
1018 *b = b_;
1019 *c = c_;
1020 *d = d_;
1021 }
1022 #endif
1023
1024 // -------------------------Runtime SSEx Detection-----------------------------
1025
1026 /* MMX is always supported per
1027 * Gecko v1.9.1 minimum CPU requirements */
1028 #define SSE1_EDX_MASK (1UL << 25)
1029 #define SSE2_EDX_MASK (1UL << 26)
1030 #define SSE3_ECX_MASK (1UL << 0)
1031
1032 static int sse_version_available(void)
1033 {
1034 #if defined(__x86_64__) || defined(__x86_64) || defined(_M_AMD64)
1035 /* we know at build time that 64-bit CPUs always have SSE2
1036 * this tells the compiler that non-SSE2 branches will never be
1037 * taken (i.e. OK to optimze away the SSE1 and non-SIMD code */
1038 return 2;
1039 #elif defined(HAS_CPUID)
1040 static int sse_version = -1;
1041 uint32_t a, b, c, d;
1042 uint32_t function = 0x00000001;
1043
1044 if (sse_version == -1) {
1045 sse_version = 0;
1046 cpuid(function, &a, &b, &c, &d);
1047 if (c & SSE3_ECX_MASK)
1048 sse_version = 3;
1049 else if (d & SSE2_EDX_MASK)
1050 sse_version = 2;
1051 else if (d & SSE1_EDX_MASK)
1052 sse_version = 1;
1053 }
1054
1055 return sse_version;
1056 #else
1057 return 0;
1058 #endif
1059 }
1060 #endif
1061
1062 static const struct matrix bradford_matrix = {{ { 0.8951f, 0.2664f,-0.1614f},
1063 {-0.7502f, 1.7135f, 0.0367f},
1064 { 0.0389f,-0.0685f, 1.0296f}},
1065 false};
1066
1067 static const struct matrix bradford_matrix_inv = {{ { 0.9869929f,-0.1470543f, 0. 1599627f},
1068 { 0.4323053f, 0.5183603f, 0. 0492912f},
1069 {-0.0085287f, 0.0400428f, 0. 9684867f}},
1070 false};
1071
1072 // See ICCv4 E.3
1073 struct matrix compute_whitepoint_adaption(float X, float Y, float Z) {
1074 float p = (0.96422f*bradford_matrix.m[0][0] + 1.000f*bradford_matrix.m[1 ][0] + 0.82521f*bradford_matrix.m[2][0]) /
1075 (X*bradford_matrix.m[0][0] + Y*bradford_matrix.m[1][0] + Z*bradford_matrix.m[2][0] );
1076 float y = (0.96422f*bradford_matrix.m[0][1] + 1.000f*bradford_matrix.m[1 ][1] + 0.82521f*bradford_matrix.m[2][1]) /
1077 (X*bradford_matrix.m[0][1] + Y*bradford_matrix.m[1][1] + Z*bradford_matrix.m[2][1] );
1078 float b = (0.96422f*bradford_matrix.m[0][2] + 1.000f*bradford_matrix.m[1 ][2] + 0.82521f*bradford_matrix.m[2][2]) /
1079 (X*bradford_matrix.m[0][2] + Y*bradford_matrix.m[1][2] + Z*bradford_matrix.m[2][2] );
1080 struct matrix white_adaption = {{ {p,0,0}, {0,y,0}, {0,0,b}}, false};
1081 return matrix_multiply( bradford_matrix_inv, matrix_multiply(white_adapt ion, bradford_matrix) );
1082 }
1083
1084 void qcms_profile_precache_output_transform(qcms_profile *profile)
1085 {
1086 /* we only support precaching on rgb profiles */
1087 if (profile->color_space != RGB_SIGNATURE)
1088 return;
1089
1090 if (qcms_supports_iccv4) {
1091 /* don't precache since we will use the B2A LUT */
1092 if (profile->B2A0)
1093 return;
1094
1095 /* don't precache since we will use the mBA LUT */
1096 if (profile->mBA)
1097 return;
1098 }
1099
1100 /* don't precache if we do not have the TRC curves */
1101 if (!profile->redTRC || !profile->greenTRC || !profile->blueTRC)
1102 return;
1103
1104 if (!profile->output_table_r) {
1105 profile->output_table_r = precache_create();
1106 if (profile->output_table_r &&
1107 !compute_precache(profile->redTRC, profile->outp ut_table_r->data)) {
1108 precache_release(profile->output_table_r);
1109 profile->output_table_r = NULL;
1110 }
1111 }
1112 if (!profile->output_table_g) {
1113 profile->output_table_g = precache_create();
1114 if (profile->output_table_g &&
1115 !compute_precache(profile->greenTRC, profile->ou tput_table_g->data)) {
1116 precache_release(profile->output_table_g);
1117 profile->output_table_g = NULL;
1118 }
1119 }
1120 if (!profile->output_table_b) {
1121 profile->output_table_b = precache_create();
1122 if (profile->output_table_b &&
1123 !compute_precache(profile->blueTRC, profile->out put_table_b->data)) {
1124 precache_release(profile->output_table_b);
1125 profile->output_table_b = NULL;
1126 }
1127 }
1128 }
1129
1130 /* Replace the current transformation with a LUT transformation using a given nu mber of sample points */
1131 qcms_transform* qcms_transform_precacheLUT_float(qcms_transform *transform, qcms _profile *in, qcms_profile *out,
1132 int samples, qcms_data_type in_ type)
1133 {
1134 /* The range between which 2 consecutive sample points can be used to in terpolate */
1135 uint16_t x,y,z;
1136 uint32_t l;
1137 uint32_t lutSize = 3 * samples * samples * samples;
1138 float* src = NULL;
1139 float* dest = NULL;
1140 float* lut = NULL;
1141 float inverse;
1142
1143 src = malloc(lutSize*sizeof(float));
1144 dest = malloc(lutSize*sizeof(float));
1145
1146 if (src && dest) {
1147 /* Prepare a list of points we want to sample: x, y, z order */
1148 l = 0;
1149 inverse = 1 / (float)(samples-1);
1150 for (x = 0; x < samples; x++) {
1151 for (y = 0; y < samples; y++) {
1152 for (z = 0; z < samples; z++) {
1153 src[l++] = x * inverse; // r
1154 src[l++] = y * inverse; // g
1155 src[l++] = z * inverse; // b
1156 }
1157 }
1158 }
1159
1160 lut = qcms_chain_transform(in, out, src, dest, lutSize);
1161
1162 if (lut) {
1163 transform->r_clut = &lut[0]; // r
1164 transform->g_clut = &lut[1]; // g
1165 transform->b_clut = &lut[2]; // b
1166 transform->grid_size = samples;
1167
1168 if (in_type == QCMS_DATA_RGBA_8) {
1169 #if defined(SSE2_ENABLE)
1170 if (sse_version_available() >= 2) {
1171 transform->transform_fn = qcms_transform _data_tetra_clut_rgba_sse2;
1172 } else {
1173 transform->transform_fn = qcms_transform _data_tetra_clut_rgba;
1174 }
1175 #else
1176 transform->transform_fn = qcms_transform_data_te tra_clut_rgba;
1177 #endif
1178 } else {
1179 transform->transform_fn = qcms_transform_data_te tra_clut;
1180 }
1181 }
1182 }
1183
1184 // XXX: qcms_modular_transform_data may return the lut in either the src or the
1185 // dest buffer. If so, it must not be free-ed.
1186 if (src && lut != src) {
1187 free(src);
1188 }
1189 if (dest && lut != dest) {
1190 free(dest);
1191 }
1192
1193 if (lut == NULL) {
1194 return NULL;
1195 }
1196 return transform;
1197 }
1198
1199 /* Create a transform LUT using the given number of sample points. The transform LUT data is stored
1200 in the output (cube) in bgra format in zyx sample order. */
1201 qcms_bool qcms_transform_create_LUT_zyx_bgra(qcms_profile *in, qcms_profile *out , qcms_intent intent,
1202 int samples, unsigned char* cube)
1203 {
1204 uint16_t z,y,x;
1205 uint32_t l,index;
1206 uint32_t lutSize = 3 * samples * samples * samples;
1207
1208 float* src = NULL;
1209 float* dest = NULL;
1210 float* lut = NULL;
1211 float inverse;
1212
1213 src = malloc(lutSize*sizeof(float));
1214 dest = malloc(lutSize*sizeof(float));
1215
1216 if (src && dest) {
1217 /* Prepare a list of points we want to sample: z, y, x order */
1218 l = 0;
1219 inverse = 1 / (float)(samples-1);
1220 for (z = 0; z < samples; z++) {
1221 for (y = 0; y < samples; y++) {
1222 for (x = 0; x < samples; x++) {
1223 src[l++] = x * inverse; // r
1224 src[l++] = y * inverse; // g
1225 src[l++] = z * inverse; // b
1226 }
1227 }
1228 }
1229
1230 lut = qcms_chain_transform(in, out, src, dest, lutSize);
1231
1232 if (lut) {
1233 index = l = 0;
1234 for (z = 0; z < samples; z++) {
1235 for (y = 0; y < samples; y++) {
1236 for (x = 0; x < samples; x++) {
1237 cube[index++] = (int)floorf(lut[ l + 2] * 255.0f + 0.5f); // b
1238 cube[index++] = (int)floorf(lut[ l + 1] * 255.0f + 0.5f); // g
1239 cube[index++] = (int)floorf(lut[ l + 0] * 255.0f + 0.5f); // r
1240 cube[index++] = 255; // a
1241 l += 3;
1242 }
1243 }
1244 }
1245 }
1246 }
1247
1248 // XXX: qcms_modular_transform_data may return the lut data in either th e src or
1249 // dest buffer so free src, dest, and lut with care.
1250
1251 if (src && lut != src)
1252 free(src);
1253 if (dest && lut != dest)
1254 free(dest);
1255
1256 if (lut) {
1257 free(lut);
1258 return true;
1259 }
1260
1261 return false;
1262 }
1263
1264 void qcms_transform_build_clut_cache(qcms_transform* transform) {
1265 const int grid_factor = transform->grid_size - 1;
1266 const float grid_scaled = (1.0f / 255.0f) * grid_factor;
1267 int i;
1268
1269 #define div_255_ceiling(value) (((value) + 254) / 255)
1270
1271 for (i = 0; i < 256; i++) {
1272 transform->ceil_cache[i] = div_255_ceiling(i * grid_factor);
1273 transform->floor_cache[i] = i * grid_factor / 255;
1274 transform->r_cache[i] = (i * grid_scaled) - transform->floor_cac he[i];
1275 }
1276
1277 #undef div_255_ceil
1278
1279 transform->transform_flags |= TRANSFORM_FLAG_CLUT_CACHE;
1280 }
1281
1282 #define NO_MEM_TRANSFORM NULL
1283
1284 qcms_transform* qcms_transform_create(
1285 qcms_profile *in, qcms_data_type in_type,
1286 qcms_profile *out, qcms_data_type out_type,
1287 qcms_intent intent)
1288 {
1289 qcms_transform *transform = NULL;
1290 bool precache = false;
1291 int i, j;
1292
1293 transform = transform_alloc();
1294 if (!transform) {
1295 return NULL;
1296 }
1297
1298 if (out_type != QCMS_DATA_RGB_8 && out_type != QCMS_DATA_RGBA_8) {
1299 assert(0 && "output type");
1300 qcms_transform_release(transform);
1301 return NULL;
1302 }
1303
1304 transform->transform_flags = 0;
1305
1306 if (out->output_table_r && out->output_table_g && out->output_table_b) {
1307 precache = true;
1308 }
1309
1310 if (qcms_supports_iccv4 && (in->A2B0 || out->B2A0 || in->mAB || out->mAB )) {
1311 // Precache the transformation to a CLUT 33x33x33 in size.
1312 // 33 is used by many profiles and works well in practice.
1313 // This evenly divides 256 into blocks of 8x8x8.
1314 // TODO For transforming small data sets of about 200x200 or les s
1315 // precaching should be avoided.
1316 qcms_transform *result = qcms_transform_precacheLUT_float(transf orm, in, out, 33, in_type);
1317 if (!result) {
1318 assert(0 && "precacheLUT failed");
1319 qcms_transform_release(transform);
1320 return NULL;
1321 }
1322 return result;
1323 }
1324
1325 /* A matrix-based transform will be selected: check that the PCS
1326 of the input/output profiles are the same, crbug.com/5120682 */
1327 if (in->pcs != out->pcs) {
1328 qcms_transform_release(transform);
1329 return NULL;
1330 }
1331
1332 if (precache) {
1333 transform->output_table_r = precache_reference(out->output_table _r);
1334 transform->output_table_g = precache_reference(out->output_table _g);
1335 transform->output_table_b = precache_reference(out->output_table _b);
1336 } else {
1337 if (!out->redTRC || !out->greenTRC || !out->blueTRC) {
1338 qcms_transform_release(transform);
1339 return NO_MEM_TRANSFORM;
1340 }
1341
1342 build_output_lut(out->redTRC, &transform->output_gamma_lut_r, &t ransform->output_gamma_lut_r_length);
1343 build_output_lut(out->greenTRC, &transform->output_gamma_lut_g, &transform->output_gamma_lut_g_length);
1344 build_output_lut(out->blueTRC, &transform->output_gamma_lut_b, & transform->output_gamma_lut_b_length);
1345
1346 if (!transform->output_gamma_lut_r || !transform->output_gamma_l ut_g || !transform->output_gamma_lut_b) {
1347 qcms_transform_release(transform);
1348 return NO_MEM_TRANSFORM;
1349 }
1350 }
1351
1352 if (in->color_space == RGB_SIGNATURE) {
1353 struct matrix in_matrix, out_matrix, result;
1354
1355 if (in_type != QCMS_DATA_RGB_8 && in_type != QCMS_DATA_RGBA_8) {
1356 assert(0 && "input type");
1357 qcms_transform_release(transform);
1358 return NULL;
1359 }
1360
1361 if (precache) {
1362 #if defined(SSE2_ENABLE)
1363 if (sse_version_available() >= 2) {
1364 if (in_type == QCMS_DATA_RGB_8)
1365 transform->transform_fn = qcms_transform _data_rgb_out_lut_sse2;
1366 else
1367 transform->transform_fn = qcms_transform _data_rgba_out_lut_sse2;
1368 } else
1369 #endif
1370 {
1371 if (in_type == QCMS_DATA_RGB_8)
1372 transform->transform_fn = qcms_transform _data_rgb_out_lut_precache;
1373 else
1374 transform->transform_fn = qcms_transform _data_rgba_out_lut_precache;
1375 }
1376 } else {
1377 if (in_type == QCMS_DATA_RGB_8)
1378 transform->transform_fn = qcms_transform_data_rg b_out_lut;
1379 else
1380 transform->transform_fn = qcms_transform_data_rg ba_out_lut;
1381 }
1382
1383 //XXX: avoid duplicating tables if we can
1384 transform->input_gamma_table_r = build_input_gamma_table(in->red TRC);
1385 transform->input_gamma_table_g = build_input_gamma_table(in->gre enTRC);
1386 transform->input_gamma_table_b = build_input_gamma_table(in->blu eTRC);
1387
1388 if (!transform->input_gamma_table_r || !transform->input_gamma_t able_g || !transform->input_gamma_table_b) {
1389 qcms_transform_release(transform);
1390 return NO_MEM_TRANSFORM;
1391 }
1392
1393 /* build combined colorant matrix */
1394 in_matrix = build_colorant_matrix(in);
1395 out_matrix = build_colorant_matrix(out);
1396 out_matrix = matrix_invert(out_matrix);
1397 if (out_matrix.invalid) {
1398 qcms_transform_release(transform);
1399 return NULL;
1400 }
1401 result = matrix_multiply(out_matrix, in_matrix);
1402
1403 /* check for NaN values in the matrix and bail if we find any
1404 see also https://bugzilla.mozilla.org/show_bug.cgi?id=1170316 */
1405 for (i = 0 ; i < 3 ; ++i) {
1406 for (j = 0 ; j < 3 ; ++j) {
1407 if (result.m[i][j] != result.m[i][j]) {
1408 qcms_transform_release(transform);
1409 return NULL;
1410 }
1411 }
1412 }
1413
1414 /* store the results in column major mode
1415 * this makes doing the multiplication with sse easier */
1416 transform->matrix[0][0] = result.m[0][0];
1417 transform->matrix[1][0] = result.m[0][1];
1418 transform->matrix[2][0] = result.m[0][2];
1419 transform->matrix[0][1] = result.m[1][0];
1420 transform->matrix[1][1] = result.m[1][1];
1421 transform->matrix[2][1] = result.m[1][2];
1422 transform->matrix[0][2] = result.m[2][0];
1423 transform->matrix[1][2] = result.m[2][1];
1424 transform->matrix[2][2] = result.m[2][2];
1425
1426 /* Flag transform as matrix. */
1427 transform->transform_flags |= TRANSFORM_FLAG_MATRIX;
1428
1429 } else if (in->color_space == GRAY_SIGNATURE) {
1430 if (in_type != QCMS_DATA_GRAY_8 && in_type != QCMS_DATA_GRAYA_8) {
1431 assert(0 && "input type");
1432 qcms_transform_release(transform);
1433 return NULL;
1434 }
1435
1436 transform->input_gamma_table_gray = build_input_gamma_table(in-> grayTRC);
1437
1438 if (!transform->input_gamma_table_gray) {
1439 qcms_transform_release(transform);
1440 return NO_MEM_TRANSFORM;
1441 }
1442
1443 if (precache) {
1444 if (in_type == QCMS_DATA_GRAY_8) {
1445 transform->transform_fn = qcms_transform_data_gr ay_out_precache;
1446 } else {
1447 transform->transform_fn = qcms_transform_data_gr aya_out_precache;
1448 }
1449 } else {
1450 if (in_type == QCMS_DATA_GRAY_8) {
1451 transform->transform_fn = qcms_transform_data_gr ay_out_lut;
1452 } else {
1453 transform->transform_fn = qcms_transform_data_gr aya_out_lut;
1454 }
1455 }
1456 } else {
1457 assert(0 && "unexpected colorspace");
1458 qcms_transform_release(transform);
1459 return NULL;
1460 }
1461
1462 return transform;
1463 }
1464
1465 /* __force_align_arg_pointer__ is an x86-only attribute, and gcc/clang warns on unused
1466 * attributes. Don't use this on ARM or AMD64. __has_attribute can detect the pr esence
1467 * of the attribute but is currently only supported by clang */
1468 #if defined(__has_attribute)
1469 #define HAS_FORCE_ALIGN_ARG_POINTER __has_attribute(__force_align_arg_pointer__)
1470 #elif defined(__GNUC__) && defined(__i386__)
1471 #define HAS_FORCE_ALIGN_ARG_POINTER 1
1472 #else
1473 #define HAS_FORCE_ALIGN_ARG_POINTER 0
1474 #endif
1475
1476 #if HAS_FORCE_ALIGN_ARG_POINTER
1477 /* we need this to avoid crashes when gcc assumes the stack is 128bit aligned */
1478 __attribute__((__force_align_arg_pointer__))
1479 #endif
1480 void qcms_transform_data(qcms_transform *transform, void *src, void *dest, size_ t length)
1481 {
1482 static const struct _qcms_format_type output_rgbx = { 0, 2 };
1483
1484 transform->transform_fn(transform, src, dest, length, output_rgbx);
1485 }
1486
1487 void qcms_transform_data_type(qcms_transform *transform, void *src, void *dest, size_t length, qcms_output_type type)
1488 {
1489 static const struct _qcms_format_type output_rgbx = { 0, 2 };
1490 static const struct _qcms_format_type output_bgrx = { 2, 0 };
1491
1492 transform->transform_fn(transform, src, dest, length, type == QCMS_OUTPU T_BGRX ? output_bgrx : output_rgbx);
1493 }
1494
1495 #define ENABLE_ICC_V4_PROFILE_SUPPORT false
1496
1497 qcms_bool qcms_supports_iccv4 = ENABLE_ICC_V4_PROFILE_SUPPORT;
1498
1499 void qcms_enable_iccv4()
1500 {
1501 qcms_supports_iccv4 = true;
1502 }
1503
1504 static inline qcms_bool transform_is_matrix(qcms_transform *t)
1505 {
1506 return (t->transform_flags & TRANSFORM_FLAG_MATRIX) ? true : false;
1507 }
1508
1509 qcms_bool qcms_transform_is_matrix(qcms_transform *t)
1510 {
1511 return transform_is_matrix(t);
1512 }
1513
1514 float qcms_transform_get_matrix(qcms_transform *t, unsigned i, unsigned j)
1515 {
1516 assert(transform_is_matrix(t) && i < 3 && j < 3);
1517
1518 // Return transform matrix element in row major order (permute i and j)
1519
1520 return t->matrix[j][i];
1521 }
1522
1523 static inline qcms_bool supported_trc_type(qcms_trc_type type)
1524 {
1525 return (type == QCMS_TRC_HALF_FLOAT || type == QCMS_TRC_USHORT);
1526 }
1527
1528 const uint16_t half_float_one = 0x3c00;
1529
1530 size_t qcms_transform_get_input_trc_rgba(qcms_transform *t, qcms_profile *in, qc ms_trc_type type, unsigned short *data)
1531 {
1532 const size_t size = 256; // The input gamma tables always have 256 entri es.
1533
1534 size_t i;
1535
1536 if (in->color_space != RGB_SIGNATURE || !supported_trc_type(type))
1537 return 0;
1538
1539 // qcms_profile *in is assumed to be the profile on the input-side of th e color transform t.
1540 // When a transform is created, the input gamma curve data is stored in the transform ...
1541
1542 if (!t->input_gamma_table_r || !t->input_gamma_table_g || !t->input_gamm a_table_b)
1543 return 0;
1544
1545 // Report the size if no output data is requested. This allows callers t o first work out the
1546 // the curve size, then provide allocated memory sufficient to store the curve rgba data.
1547
1548 if (!data)
1549 return size;
1550
1551 switch(type) {
1552 case QCMS_TRC_HALF_FLOAT:
1553 for (i = 0; i < size; ++i) {
1554 *data++ = float_to_half_float(t->input_gamma_tab le_r[i]); // r
1555 *data++ = float_to_half_float(t->input_gamma_tab le_g[i]); // g
1556 *data++ = float_to_half_float(t->input_gamma_tab le_b[i]); // b
1557 *data++ = half_float_one; // a
1558 }
1559 break;
1560 case QCMS_TRC_USHORT:
1561 for (i = 0; i < size; ++i) {
1562 *data++ = roundf(t->input_gamma_table_r[i] * 655 35.0); // r
1563 *data++ = roundf(t->input_gamma_table_g[i] * 655 35.0); // g
1564 *data++ = roundf(t->input_gamma_table_b[i] * 655 35.0); // b
1565 *data++ = 65535; // a
1566 }
1567 break;
1568 default:
1569 /* should not be reached */
1570 assert(0);
1571 }
1572
1573 return size;
1574 }
1575
1576 const float inverse65535 = (float) (1.0 / 65535.0);
1577
1578 size_t qcms_transform_get_output_trc_rgba(qcms_transform *t, qcms_profile *out, qcms_trc_type type, unsigned short *data)
1579 {
1580 size_t size, i;
1581
1582 if (out->color_space != RGB_SIGNATURE || !supported_trc_type(type))
1583 return 0;
1584
1585 // qcms_profile *out is assumed to be the profile on the output-side of the transform t.
1586 // If the transform output gamma curves need building, do that. They're usually built when
1587 // the transform was created, but sometimes not due to the output gamma precache ...
1588
1589 if (!out->redTRC || !out->greenTRC || !out->blueTRC)
1590 return 0;
1591 if (!t->output_gamma_lut_r)
1592 build_output_lut(out->redTRC, &t->output_gamma_lut_r, &t->output _gamma_lut_r_length);
1593 if (!t->output_gamma_lut_g)
1594 build_output_lut(out->greenTRC, &t->output_gamma_lut_g, &t->outp ut_gamma_lut_g_length);
1595 if (!t->output_gamma_lut_b)
1596 build_output_lut(out->blueTRC, &t->output_gamma_lut_b, &t->outpu t_gamma_lut_b_length);
1597
1598 if (!t->output_gamma_lut_r || !t->output_gamma_lut_g || !t->output_gamma _lut_b)
1599 return 0;
1600
1601 // Output gamma tables should have the same size and should have 4096 en tries at most (the
1602 // minimum is 256). Larger tables are rare and ignored here: fail by ret urning 0.
1603
1604 size = t->output_gamma_lut_r_length;
1605 if (size != t->output_gamma_lut_g_length)
1606 return 0;
1607 if (size != t->output_gamma_lut_b_length)
1608 return 0;
1609 if (size < 256 || size > 4096)
1610 return 0;
1611
1612 // Report the size if no output data is requested. This allows callers t o first work out the
1613 // the curve size, then provide allocated memory sufficient to store the curve rgba data.
1614
1615 if (!data)
1616 return size;
1617
1618 switch (type) {
1619 case QCMS_TRC_HALF_FLOAT:
1620 for (i = 0; i < size; ++i) {
1621 *data++ = float_to_half_float(t->output_gamma_lu t_r[i] * inverse65535); // r
1622 *data++ = float_to_half_float(t->output_gamma_lu t_g[i] * inverse65535); // g
1623 *data++ = float_to_half_float(t->output_gamma_lu t_b[i] * inverse65535); // b
1624 *data++ = half_float_one; // a
1625 }
1626 break;
1627 case QCMS_TRC_USHORT:
1628 for (i = 0; i < size; ++i) {
1629 *data++ = t->output_gamma_lut_r[i]; // r
1630 *data++ = t->output_gamma_lut_g[i]; // g
1631 *data++ = t->output_gamma_lut_b[i]; // b
1632 *data++ = 65535; // a
1633 }
1634 break;
1635 default:
1636 /* should not be reached */
1637 assert(0);
1638 }
1639
1640 return size;
1641 }
OLDNEW
« no previous file with comments | « third_party/qcms/src/tests/timing.h ('k') | third_party/qcms/src/transform-sse2.c » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698