Bug 497363. qcms: Use a minimum of 256 entries when calling invert_lut. r=joedrew
authorJeff Muizelaar <jmuizelaar@mozilla.com>
Fri, 12 Jun 2009 14:38:30 -0400
changeset 29149 f6609f07b14f6b39dfd2a18f0def27bbb2c6393e
parent 29148 74959aad851c807d231d44873f6c24b23e80eac5
child 29150 b07348ce9233912fdb7f143150320cd066edbbc1
push id7446
push userjmuizelaar@mozilla.com
push dateFri, 12 Jun 2009 18:40:44 +0000
treeherdermozilla-central@18c9c79509c1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersjoedrew
bugs497363
milestone1.9.2a1pre
Bug 497363. qcms: Use a minimum of 256 entries when calling invert_lut. r=joedrew Makes the number of output entries produced by invert_lut() a parameter and changes all callers to use a minimum of 256 entries when computing the inverse.
gfx/qcms/transform.c
--- a/gfx/qcms/transform.c
+++ b/gfx/qcms/transform.c
@@ -542,27 +542,40 @@ qcms_bool set_rgb_colorants(qcms_profile
 
 	profile->blueColorant.X = double_to_s15Fixed16Number(colorants.m[0][2]);
 	profile->blueColorant.Y = double_to_s15Fixed16Number(colorants.m[1][2]);
 	profile->blueColorant.Z = double_to_s15Fixed16Number(colorants.m[2][2]);
 
 	return true;
 }
 
-static uint16_t *invert_lut(uint16_t *table, int length)
+/*
+ The number of entries needed to invert a lookup table should not
+ necessarily be the same as the original number of entries.  This is
+ especially true of lookup tables that have a small number of entries.
+
+ For example:
+ Using a table like:
+    {0, 3104, 14263, 34802, 65535}
+ invert_lut will produce an inverse of:
+    {3, 34459, 47529, 56801, 65535}
+ which has an maximum error of about 9855 (pixel difference of ~38.346)
+
+ For now, we punt the decision of output size to the caller. */
+static uint16_t *invert_lut(uint16_t *table, int length, int out_length)
 {
 	int i;
-	/* for now we invert the lut by creating a lut of the same size
+	/* for now we invert the lut by creating a lut of size out_length
 	 * and attempting to lookup a value for each entry using lut_inverse_interp16 */
-	uint16_t *output = malloc(sizeof(uint16_t)*length);
+	uint16_t *output = malloc(sizeof(uint16_t)*out_length);
 	if (!output)
 		return NULL;
 
-	for (i = 0; i < length; i++) {
-		double x = ((double) i * 65535.) / (double) (length - 1);
+	for (i = 0; i < out_length; i++) {
+		double x = ((double) i * 65535.) / (double) (out_length - 1);
 		uint16_fract_t input = floor(x + .5);
 		output[i] = lut_inverse_interp16(input, table, length);
 	}
 	return output;
 }
 
 static uint16_t *build_linear_table(int length)
 {
@@ -1340,20 +1353,27 @@ void compute_precache_linear(uint8_t *ou
 
 qcms_bool compute_precache(struct curveType *trc, uint8_t *output)
 {
 	if (trc->count == 0) {
 		compute_precache_linear(output);
 	} else if (trc->count == 1) {
 		compute_precache_pow(output, 1./u8Fixed8Number_to_float(trc->data[0]));
 	} else {
-		uint16_t *inverted = invert_lut(trc->data, trc->count);
+		uint16_t *inverted;
+		int inverted_size = trc->count;
+		//XXX: the choice of a minimum of 256 here is not backed by any theory, measurement or data, however it is what lcms uses.
+		// the maximum number we would need is 65535 because that's the accuracy used for computing the precache table
+		if (inverted_size < 256)
+			inverted_size = 256;
+
+		inverted = invert_lut(trc->data, trc->count, inverted_size);
 		if (!inverted)
 			return false;
-		compute_precache_lut(output, inverted, trc->count);
+		compute_precache_lut(output, inverted, inverted_size);
 		free(inverted);
 	}
 	return true;
 }
 
 
 // Determine if we can build with SSE2 (this was partly copied from jmorecfg.h in
 // mozilla/jpeg)
@@ -1418,30 +1438,33 @@ static qcms_bool sse2_available(void)
                      has_sse2 = 0;
        }
 
        return has_sse2;
 #endif
        return false;
 }
 
-
 void build_output_lut(struct curveType *trc,
 		uint16_t **output_gamma_lut, size_t *output_gamma_lut_length)
 {
 	if (trc->count == 0) {
 		*output_gamma_lut = build_linear_table(4096);
 		*output_gamma_lut_length = 4096;
 	} else if (trc->count == 1) {
 		float gamma = 1./u8Fixed8Number_to_float(trc->data[0]);
 		*output_gamma_lut = build_pow_table(gamma, 4096);
 		*output_gamma_lut_length = 4096;
 	} else {
-		*output_gamma_lut = invert_lut(trc->data, trc->count);
+		//XXX: the choice of a minimum of 256 here is not backed by any theory, measurement or data, however it is what lcms uses.
 		*output_gamma_lut_length = trc->count;
+		if (*output_gamma_lut_length < 256)
+			*output_gamma_lut_length = 256;
+
+		*output_gamma_lut = invert_lut(trc->data, trc->count, *output_gamma_lut_length);
 	}
 
 }
 
 void qcms_profile_precache_output_transform(qcms_profile *profile)
 {
 	/* we only support precaching on rgb profiles */
 	if (profile->color_space != RGB_SIGNATURE)