summaryrefslogtreecommitdiff
path: root/babl
diff options
context:
space:
mode:
Diffstat (limited to 'babl')
-rw-r--r--babl/babl-cache.c174
-rw-r--r--babl/babl-classes.h2
-rw-r--r--babl/babl-core.c181
-rw-r--r--babl/babl-cpuaccel.c98
-rw-r--r--babl/babl-cpuaccel.h48
-rw-r--r--babl/babl-extension.c91
-rw-r--r--babl/babl-extension.h3
-rw-r--r--babl/babl-fish-path.c652
-rw-r--r--babl/babl-fish-reference.c2
-rw-r--r--babl/babl-fish.c7
-rw-r--r--babl/babl-fish.h3
-rw-r--r--babl/babl-format.c26
-rw-r--r--babl/babl-icc.c116
-rw-r--r--babl/babl-internal.c4
-rw-r--r--babl/babl-internal.h22
-rw-r--r--babl/babl-introspect.c2
-rw-r--r--babl/babl-matrix.h18
-rw-r--r--babl/babl-memory.c4
-rw-r--r--babl/babl-model.c28
-rw-r--r--babl/babl-palette.c7
-rw-r--r--babl/babl-ref-pixels.inc10
-rw-r--r--babl/babl-space.c719
-rw-r--r--babl/babl-space.h5
-rw-r--r--babl/babl-util.c306
-rw-r--r--babl/babl-util.h60
-rw-r--r--babl/babl.c176
-rw-r--r--babl/babl.h28
-rw-r--r--babl/babl/meson.build9
-rw-r--r--babl/base/babl-base.c26
-rw-r--r--babl/base/babl-base.h42
-rw-r--r--babl/base/babl-rgb-converter.c536
-rw-r--r--babl/base/babl-trc.c (renamed from babl/babl-trc.c)404
-rw-r--r--babl/base/babl-trc.h (renamed from babl/babl-trc.h)8
-rw-r--r--babl/base/formats.c4
-rw-r--r--babl/base/meson.build35
-rw-r--r--babl/base/model-cmyk.c2
-rw-r--r--babl/base/model-gray.c3
-rw-r--r--babl/base/model-rgb.c2
-rw-r--r--babl/base/model-ycbcr.c2
-rw-r--r--babl/base/pow-24.h7
-rw-r--r--babl/base/type-float.c2
-rw-r--r--babl/base/type-half.c2
-rw-r--r--babl/base/type-u15.c2
-rw-r--r--babl/base/type-u16.c2
-rw-r--r--babl/base/type-u32.c6
-rw-r--r--babl/base/type-u8.c2
-rw-r--r--babl/base/util.h18
-rw-r--r--babl/git-version.h6
-rw-r--r--babl/git-version.h.in6
-rw-r--r--babl/meson.build74
50 files changed, 2776 insertions, 1216 deletions
diff --git a/babl/babl-cache.c b/babl/babl-cache.c
index 63ae19e..efdce3f 100644
--- a/babl/babl-cache.c
+++ b/babl/babl-cache.c
@@ -35,72 +35,112 @@
static int
mk_ancestry_iter (const char *path)
{
- char copy[4096];
- strncpy (copy, path, 4096);
- copy[sizeof (copy) - 1] = '\0';
- if (strrchr (copy, '/'))
+ char *copy = babl_strdup (path);
+ char *rchr = NULL;
+ int result = 0;
+
+ if (!copy)
+ return -1;
+
+ rchr = strrchr (copy, '/');
+ if (rchr)
{
- *strrchr (copy, '/') = '\0';
+ *rchr = '\0';
+
if (copy[0])
{
- struct stat stat_buf;
- if ( ! (stat (copy, &stat_buf)==0 && S_ISDIR(stat_buf.st_mode)))
- {
- if (mk_ancestry_iter (copy) != 0)
- return -1;
-#ifndef _WIN32
- return mkdir (copy, S_IRWXU);
-#else
- return mkdir (copy);
-#endif
- }
+ BablStat stat_buf;
+ if ( ! (_babl_stat (copy, &stat_buf)==0 && S_ISDIR(stat_buf.st_mode)))
+ result = mk_ancestry_iter (copy) == 0 ? _babl_mkdir (copy, S_IRWXU) : -1;
}
}
- return 0;
+
+ babl_free (copy);
+ return result;
}
static int
mk_ancestry (const char *path)
{
- char copy[4096];
- strncpy (copy, path, 4096);
- copy[sizeof (copy) - 1] = '\0';
+ char *copy = babl_strdup (path);
+ int result = 0;
+
+ if (!copy)
+ return -1;
+
#ifdef _WIN32
for (char *c = copy; *c; c++)
if (*c == '\\')
*c = '/';
#endif
- return mk_ancestry_iter (copy);
+
+ result = mk_ancestry_iter (copy);
+
+ babl_free (copy);
+ return result;
}
-static const char *
+static char *
fish_cache_path (void)
{
- struct stat stat_buf;
- static char path[4096];
+ char *path = NULL;
+ char buf[4096];
+ BablStat stat_buf;
- strncpy (path, FALLBACK_CACHE_PATH, 4096);
- path[sizeof (path) - 1] = '\0';
#ifndef _WIN32
+
+ strncpy (buf, FALLBACK_CACHE_PATH, 4096);
+ buf[sizeof (buf) - 1] = '\0';
+
if (getenv ("XDG_CACHE_HOME"))
- snprintf (path, sizeof (path), "%s/babl/babl-fishes", getenv("XDG_CACHE_HOME"));
+ snprintf (buf, sizeof (buf), "%s/babl/babl-fishes", getenv("XDG_CACHE_HOME"));
else if (getenv ("HOME"))
- snprintf (path, sizeof (path), "%s/.cache/babl/babl-fishes", getenv("HOME"));
+ snprintf (buf, sizeof (buf), "%s/.cache/babl/babl-fishes", getenv("HOME"));
+
+ path = babl_strdup (buf);
+
#else
-{
- char win32path[4096];
- if (SHGetFolderPathA (NULL, CSIDL_LOCAL_APPDATA, NULL, SHGFP_TYPE_CURRENT, win32path) == S_OK)
- snprintf (path, sizeof (path), "%s\\%s\\babl-fishes.txt", win32path, BABL_LIBRARY);
+
+ wchar_t *appdata_utf16 = NULL;
+
+ if (SHGetKnownFolderPath (&FOLDERID_LocalAppData, KF_FLAG_DEFAULT, NULL, &appdata_utf16) == S_OK)
+ {
+ char *appdata = babl_convert_utf16_to_utf8 (appdata_utf16);
+
+ if (appdata && appdata[0])
+ {
+ const char *fmt = "%s\\%s\\babl-fishes.txt";
+ size_t sz = add_check_overflow (3, strlen (fmt), strlen (appdata), strlen (BABL_LIBRARY));
+
+ if (sz > 0 && (path = babl_malloc (sz)) != NULL)
+ _snprintf_s (path, sz, sz, fmt, appdata, BABL_LIBRARY);
+ }
+
+ if (appdata)
+ babl_free (appdata);
+ }
else if (getenv ("TEMP"))
- snprintf (path, sizeof (path), "%s\\babl-fishes.txt", getenv("TEMP"));
-}
+ {
+ snprintf (buf, sizeof (buf), "%s\\babl-fishes.txt", getenv("TEMP"));
+ path = babl_strdup (buf);
+ }
+
+ if (appdata_utf16)
+ {
+ CoTaskMemFree (appdata_utf16);
+ appdata_utf16 = NULL;
+ }
+
#endif
- if (stat (path, &stat_buf)==0 && S_ISREG(stat_buf.st_mode))
+ if (!path)
+ return babl_strdup (FALLBACK_CACHE_PATH);
+
+ if (_babl_stat (path, &stat_buf) == 0 && S_ISREG(stat_buf.st_mode))
return path;
if (mk_ancestry (path) != 0)
- return FALLBACK_CACHE_PATH;
+ return babl_strdup (FALLBACK_CACHE_PATH);
return path;
}
@@ -177,23 +217,23 @@ cache_header (void)
return buf;
}
-void
+void
babl_store_db (void)
{
BablDb *db = babl_fish_db ();
- int i;
+ char *cache_path = fish_cache_path ();
char *tmpp = calloc(8000,1);
- FILE *dbfile;
+ FILE *dbfile = NULL;
+ int i;
+
+ if (!cache_path || !tmpp)
+ goto cleanup;
- if (!tmpp)
- return;
- snprintf (tmpp, 8000, "%s~", fish_cache_path ());
- dbfile = fopen (tmpp, "w");
+ snprintf (tmpp, 8000, "%s~", cache_path);
+ dbfile = _babl_fopen (tmpp, "w");
if (!dbfile)
- {
- free (tmpp);
- return;
- }
+ goto cleanup;
+
fprintf (dbfile, "%s\n", cache_header ());
/* sort the list of fishes by usage, making next run more efficient -
@@ -209,13 +249,24 @@ babl_store_db (void)
if (babl_fish_serialize (fish, tmp, 4096))
fprintf (dbfile, "%s----\n", tmp);
}
+
fclose (dbfile);
+ dbfile = NULL;
#ifdef _WIN32
- remove (fish_cache_path ());
+ _babl_remove (cache_path);
#endif
- rename (tmpp, fish_cache_path());
- free (tmpp);
+ _babl_rename (tmpp, cache_path);
+
+cleanup:
+ if (dbfile)
+ fclose (dbfile);
+
+ if (cache_path)
+ babl_free (cache_path);
+
+ if (tmpp)
+ free (tmpp);
}
int
@@ -230,7 +281,7 @@ _babl_fish_create_name (char *buf,
void
babl_init_db (void)
{
- const char *path = fish_cache_path ();
+ char *path = fish_cache_path ();
long length = -1;
char seps[] = "\n\r";
Babl *babl = NULL;
@@ -242,11 +293,11 @@ babl_init_db (void)
time_t tim = time (NULL);
if (getenv ("BABL_DEBUG_CONVERSIONS"))
- return;
+ goto cleanup;
_babl_file_get_contents (path, &contents, &length, NULL);
if (!contents)
- return;
+ goto cleanup;
token = strtok_r (contents, seps, &tokp);
while( token != NULL )
@@ -274,10 +325,7 @@ babl_init_db (void)
/* if babl has changed in git .. drop whole cache */
{
if (strcmp ( token, cache_header ()))
- {
- free (contents);
- return;
- }
+ goto cleanup;
}
break;
case '\t':
@@ -294,8 +342,7 @@ babl_init_db (void)
{
fprintf (stderr, "%s:%i: loading of cache failed\n",
__FUNCTION__, __LINE__);
- free (contents);
- return;
+ goto cleanup;
}
if (strstr (token, "[reference]"))
@@ -334,7 +381,6 @@ babl_init_db (void)
babl->fish.source = from_format;
babl->fish.destination = to_format;
babl->fish_path.conversion_list = babl_list_init_with_size (10);
- _babl_fish_prepare_bpp (babl);
_babl_fish_rig_dispatch (babl);
}
@@ -348,7 +394,10 @@ babl_init_db (void)
else if (!strncmp (token2, "cost=", 5))
{
if (babl->class_type == BABL_FISH_PATH)
+ {
babl->fish_path.cost = babl_parse_double (token2 + 5);
+ _babl_fish_prepare_bpp (babl);
+ }
}
else if (!strncmp (token2, "pixels=", 7))
{
@@ -382,6 +431,11 @@ babl_init_db (void)
}
token = strtok_r (NULL, seps, &tokp);
}
+
+cleanup:
if (contents)
free (contents);
+
+ if (path)
+ babl_free (path);
}
diff --git a/babl/babl-classes.h b/babl/babl-classes.h
index c25172a..cf03447 100644
--- a/babl/babl-classes.h
+++ b/babl/babl-classes.h
@@ -59,7 +59,7 @@ enum {
#include "babl-type.h"
#include "babl-sampling.h"
-#include "babl-trc.h"
+#include "base/babl-trc.h"
#include "babl-space.h"
#include "babl-component.h"
#include "babl-model.h"
diff --git a/babl/babl-core.c b/babl/babl-core.c
index d78b5e5..2bd36c7 100644
--- a/babl/babl-core.c
+++ b/babl/babl-core.c
@@ -162,3 +162,184 @@ babl_core_init (void)
NULL
);
}
+
+
+/////////////////// temporary here
+///////////////////
+
+const Babl *
+babl_trc_lut (const char *name,
+ int n,
+ float *entries)
+{
+ return babl_trc_new (name, BABL_TRC_LUT, 0, n, entries);
+}
+
+
+const Babl *
+babl_trc_formula_srgb (double g,
+ double a,
+ double b,
+ double c,
+ double d,
+ double e,
+ double f)
+{
+ char name[128];
+ int i;
+ float params[7]={g, a, b, c, d, e, f};
+
+ if (fabs (g - 2.400) < 0.01 &&
+ fabs (a - 0.947) < 0.01 &&
+ fabs (b - 0.052) < 0.01 &&
+ fabs (c - 0.077) < 0.01 &&
+ fabs (d - 0.040) < 0.01 &&
+ fabs (e - 0.000) < 0.01 &&
+ fabs (f - 0.000) < 0.01
+ )
+ return babl_trc ("sRGB");
+
+ snprintf (name, sizeof (name), "%.6f %.6f %.4f %.4f %.4f %.4f %.4f", g, a, b, c, d, e, f);
+ for (i = 0; name[i]; i++)
+ if (name[i] == ',') name[i] = '.';
+ while (name[strlen(name)-1]=='0')
+ name[strlen(name)-1]='\0';
+ return babl_trc_new (name, BABL_TRC_FORMULA_SRGB, g, 0, params);
+}
+
+const Babl *
+babl_trc_formula_cie (double g,
+ double a,
+ double b,
+ double c)
+{
+ char name[128];
+ int i;
+ float params[4]={g, a, b, c};
+
+ snprintf (name, sizeof (name), "%.6f %.6f %.4f %.4f", g, a, b, c);
+ for (i = 0; name[i]; i++)
+ if (name[i] == ',') name[i] = '.';
+ while (name[strlen(name)-1]=='0')
+ name[strlen(name)-1]='\0';
+ return babl_trc_new (name, BABL_TRC_FORMULA_CIE, g, 0, params);
+}
+
+
+const Babl *
+babl_trc_gamma (double gamma)
+{
+ char name[32];
+ int i;
+ if (fabs (gamma - 1.0) < 0.01)
+ return babl_trc_new ("linear", BABL_TRC_LINEAR, 1.0, 0, NULL);
+
+ snprintf (name, sizeof (name), "%.6f", gamma);
+ for (i = 0; name[i]; i++)
+ if (name[i] == ',') name[i] = '.';
+ while (name[strlen(name)-1]=='0')
+ name[strlen(name)-1]='\0';
+ return babl_trc_new (name, BABL_TRC_FORMULA_GAMMA, gamma, 0, NULL);
+}
+
+void
+babl_trc_class_init (void)
+{
+ babl_trc_new ("sRGB", BABL_TRC_SRGB, 2.2, 0, NULL);
+ babl_trc_gamma (2.2);
+ babl_trc_gamma (1.8);
+ babl_trc_gamma (1.0);
+ babl_trc_new ("linear", BABL_TRC_LINEAR, 1.0, 0, NULL);
+}
+
+#if 0
+float
+babl_trc_from_linear (const Babl *trc_,
+ float value)
+{
+ return babl_trc_from_linear (trc_, value);
+}
+
+float
+babl_trc_to_linear (const Babl *trc_,
+ float value)
+{
+ return babl_trc_to_linear (trc_, value);
+}
+#endif
+
+static int
+babl_lut_match_gamma (float *lut,
+ int lut_size,
+ float gamma)
+{
+ int match = 1;
+ int i;
+ if (lut_size > 1024)
+ {
+ for (i = 0; match && i < lut_size; i++)
+ {
+ if (fabs (lut[i] - pow ((i / (lut_size-1.0)), gamma)) > 0.0001)
+ match = 0;
+ }
+ }
+ else
+ {
+ for (i = 0; match && i < lut_size; i++)
+ {
+ if (fabs (lut[i] - pow ((i / (lut_size-1.0)), gamma)) > 0.001)
+ match = 0;
+ }
+ }
+ return match;
+}
+
+const Babl *
+babl_trc_lut_find (float *lut,
+ int lut_size)
+{
+ int i;
+ int match = 1;
+
+ /* look for linear match */
+ for (i = 0; match && i < lut_size; i++)
+ if (fabs (lut[i] - i / (lut_size-1.0)) > 0.015)
+ match = 0;
+ if (match)
+ return babl_trc_gamma (1.0);
+
+ /* look for sRGB match: */
+ match = 1;
+ if (lut_size > 1024)
+ {
+ for (i = 0; match && i < lut_size; i++)
+ {
+ if (fabs (lut[i] - gamma_2_2_to_linear (i / (lut_size-1.0))) > 0.0001)
+ match = 0;
+ }
+ }
+ else
+ {
+ for (i = 0; match && i < lut_size; i++)
+ {
+ if (fabs (lut[i] - gamma_2_2_to_linear (i / (lut_size-1.0))) > 0.001)
+ match = 0;
+ }
+ }
+ if (match)
+ return babl_trc ("sRGB");
+
+ if (babl_lut_match_gamma (lut, lut_size, 2.2))
+ return babl_trc_gamma(2.2);
+
+ if (babl_lut_match_gamma (lut, lut_size, 1.8))
+ return babl_trc_gamma(1.8);
+
+ return NULL;
+}
+
+const Babl * babl_trc (const char *name)
+{
+ return babl_trc_lookup_by_name (name);
+}
+
diff --git a/babl/babl-cpuaccel.c b/babl/babl-cpuaccel.c
index ef26fa5..2cfff1b 100644
--- a/babl/babl-cpuaccel.c
+++ b/babl/babl-cpuaccel.c
@@ -14,11 +14,10 @@
* You should have received a copy of the GNU Lesser General
* Public License along with this library; if not, see
* <https://www.gnu.org/licenses/>.
+ *
+ * (c) Manish Singh, Aaron Holtzman, Jan Heller, Ell, Øyvind Kolås
*/
-/*
- * x86 bits Copyright (C) Manish Singh <yosh@gimp.org>
- */
/*
* PPC CPU acceleration detection was taken from DirectFB but seems to be
@@ -78,7 +77,6 @@ babl_cpu_accel_set_use (gboolean use)
#define HAVE_ACCEL 1
-
typedef enum
{
ARCH_X86_VENDOR_NONE,
@@ -117,15 +115,26 @@ enum
{
ARCH_X86_INTEL_FEATURE_PNI = 1 << 0,
ARCH_X86_INTEL_FEATURE_SSSE3 = 1 << 9,
+ ARCH_X86_INTEL_FEATURE_FMA = 1 << 12,
ARCH_X86_INTEL_FEATURE_SSE4_1 = 1 << 19,
ARCH_X86_INTEL_FEATURE_SSE4_2 = 1 << 20,
+ ARCH_X86_INTEL_FEATURE_MOVBE = 1 << 22,
+ ARCH_X86_INTEL_FEATURE_POPCNT = 1 << 23,
+ ARCH_X86_INTEL_FEATURE_XSAVE = 1 << 26,
+ ARCH_X86_INTEL_FEATURE_OSXSAVE = 1 << 27,
ARCH_X86_INTEL_FEATURE_AVX = 1 << 28,
ARCH_X86_INTEL_FEATURE_F16C = 1 << 29,
- /* extended features */
- ARCH_X86_INTEL_FEATURE_AVX2 = 1 << 5
+ // extended features
+
+ ARCH_X86_INTEL_FEATURE_BMI1 = 1 << 3,
+ ARCH_X86_INTEL_FEATURE_BMI2 = 1 << 8,
+ ARCH_X86_INTEL_FEATURE_AVX2 = 1 << 5,
};
+
+/* x86 asm bit Copyright (C) Manish Singh <yosh@gimp.org>
+ */
#if !defined(ARCH_X86_64) && (defined(PIC) || defined(__PIC__))
#define cpuid(op,eax,ebx,ecx,edx) \
__asm__ ("movl %%ebx, %%esi\n\t" \
@@ -136,7 +145,7 @@ enum
"=S" (ebx), \
"=c" (ecx), \
"=d" (edx) \
- : "0" (op))
+ : "0" (op), "2" (0))
#else
#define cpuid(op,eax,ebx,ecx,edx) \
__asm__ ("xor %%ecx, %%ecx\n\t" \
@@ -145,7 +154,7 @@ enum
"=b" (ebx), \
"=c" (ecx), \
"=d" (edx) \
- : "0" (op))
+ : "0" (op), "2" (0))
#endif
@@ -256,19 +265,43 @@ arch_accel_intel (void)
if (ecx & ARCH_X86_INTEL_FEATURE_SSE4_1)
caps |= BABL_CPU_ACCEL_X86_SSE4_1;
+ if (ecx & ARCH_X86_INTEL_FEATURE_SSE4_2)
+ caps |= BABL_CPU_ACCEL_X86_SSE4_2;
+
+ if (ecx & ARCH_X86_INTEL_FEATURE_AVX)
+ caps |= BABL_CPU_ACCEL_X86_AVX;
+
+ if (ecx & ARCH_X86_INTEL_FEATURE_POPCNT)
+ caps |= BABL_CPU_ACCEL_X86_POPCNT;
+
+ if (ecx & ARCH_X86_INTEL_FEATURE_XSAVE)
+ caps |= BABL_CPU_ACCEL_X86_XSAVE;
+
+ if (ecx & ARCH_X86_INTEL_FEATURE_OSXSAVE)
+ caps |= BABL_CPU_ACCEL_X86_OSXSAVE;
+
+ if (ecx & ARCH_X86_INTEL_FEATURE_FMA)
+ caps |= BABL_CPU_ACCEL_X86_FMA;
+
if (ecx & ARCH_X86_INTEL_FEATURE_F16C)
caps |= BABL_CPU_ACCEL_X86_F16C;
- cpuid (0, eax, ebx, ecx, edx);
+ if (ecx & ARCH_X86_INTEL_FEATURE_MOVBE)
+ caps |= BABL_CPU_ACCEL_X86_MOVBE;
+ cpuid (0, eax, ebx, ecx, edx);
if (eax >= 7)
- {
- cpuid (7, eax, ebx, ecx, edx);
-
- if (ebx & ARCH_X86_INTEL_FEATURE_AVX2)
- caps |= BABL_CPU_ACCEL_X86_AVX2;
- }
+ {
+ cpuid (7, eax, ebx, ecx, edx);
+ if (ebx & ARCH_X86_INTEL_FEATURE_AVX2)
+ caps |= BABL_CPU_ACCEL_X86_AVX2;
+ if (ebx & ARCH_X86_INTEL_FEATURE_BMI1)
+ caps |= BABL_CPU_ACCEL_X86_BMI1;
+ if (ebx & ARCH_X86_INTEL_FEATURE_BMI2)
+ caps |= BABL_CPU_ACCEL_X86_BMI2;
+ }
#endif /* USE_SSE */
+
}
#endif /* USE_MMX */
@@ -517,6 +550,41 @@ arch_accel (void)
#endif /* ARCH_PPC && USE_ALTIVEC */
+#if defined(ARCH_ARM)
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <elf.h>
+
+#define HAVE_ACCEL 1
+
+static guint32
+arch_accel (void)
+{
+ /* TODO : add or hardcode the other ways it can be on arm, where
+ * this info comes from the system and not from running cpu
+ * instructions
+ */
+ int has_neon = 0;
+ int fd = open ("/proc/self/auxv", O_RDONLY);
+ Elf32_auxv_t auxv;
+ if (fd >= 0)
+ {
+ while (read (fd, &auxv, sizeof (Elf32_auxv_t)) == sizeof (Elf32_auxv_t))
+ {
+ if (auxv.a_type == AT_HWCAP)
+ {
+ if (auxv.a_un.a_val & 4096)
+ has_neon = 1;
+ }
+ }
+ close (fd);
+ }
+ return has_neon?BABL_CPU_ACCEL_ARM_NEON:0;
+}
+
+#endif /* ARCH_ARM */
static BablCpuAccelFlags
cpu_accel (void)
diff --git a/babl/babl-cpuaccel.h b/babl/babl-cpuaccel.h
index b8a6855..133d138 100644
--- a/babl/babl-cpuaccel.h
+++ b/babl/babl-cpuaccel.h
@@ -24,25 +24,55 @@ typedef enum
BABL_CPU_ACCEL_NONE = 0x0,
/* x86 accelerations */
- BABL_CPU_ACCEL_X86_MMX = 0x01000000,
+ BABL_CPU_ACCEL_X86_MMX = 0x80000000,
BABL_CPU_ACCEL_X86_3DNOW = 0x40000000,
BABL_CPU_ACCEL_X86_MMXEXT = 0x20000000,
BABL_CPU_ACCEL_X86_SSE = 0x10000000,
BABL_CPU_ACCEL_X86_SSE2 = 0x08000000,
- BABL_CPU_ACCEL_X86_SSE3 = 0x02000000,
- BABL_CPU_ACCEL_X86_SSSE3 = 0x00800000,
- BABL_CPU_ACCEL_X86_SSE4_1 = 0x00400000,
- /* BABL_CPU_ACCEL_X86_SSE4_2 = 0x00200000, */
- /* BABL_CPU_ACCEL_X86_AVX = 0x00080000, */
+ BABL_CPU_ACCEL_X86_SSE3 = 0x04000000,
+ BABL_CPU_ACCEL_X86_SSSE3 = 0x02000000,
+ BABL_CPU_ACCEL_X86_SSE4_1 = 0x01000000,
+ BABL_CPU_ACCEL_X86_SSE4_2 = 0x00800000,
+ BABL_CPU_ACCEL_X86_AVX = 0x00400000,
+ BABL_CPU_ACCEL_X86_POPCNT = 0x00200000,
+ BABL_CPU_ACCEL_X86_FMA = 0x00100000,
+ BABL_CPU_ACCEL_X86_MOVBE = 0x00080000,
BABL_CPU_ACCEL_X86_F16C = 0x00040000,
- BABL_CPU_ACCEL_X86_AVX2 = 0x00020000,
+ BABL_CPU_ACCEL_X86_XSAVE = 0x00020000,
+ BABL_CPU_ACCEL_X86_OSXSAVE = 0x00010000,
+ BABL_CPU_ACCEL_X86_BMI1 = 0x00008000,
+ BABL_CPU_ACCEL_X86_BMI2 = 0x00004000,
+ BABL_CPU_ACCEL_X86_AVX2 = 0x00002000,
+
+ BABL_CPU_ACCEL_X86_64_V2 =
+ (BABL_CPU_ACCEL_X86_POPCNT|
+ BABL_CPU_ACCEL_X86_SSE4_1|
+ BABL_CPU_ACCEL_X86_SSE4_2|
+ BABL_CPU_ACCEL_X86_SSSE3),
+
+ BABL_CPU_ACCEL_X86_64_V3 =
+ (BABL_CPU_ACCEL_X86_64_V2|
+ BABL_CPU_ACCEL_X86_BMI1|
+ BABL_CPU_ACCEL_X86_BMI2|
+ BABL_CPU_ACCEL_X86_AVX|
+ BABL_CPU_ACCEL_X86_FMA|
+ BABL_CPU_ACCEL_X86_F16C|
+ BABL_CPU_ACCEL_X86_AVX2|
+ BABL_CPU_ACCEL_X86_OSXSAVE|
+ BABL_CPU_ACCEL_X86_MOVBE),
/* powerpc accelerations */
- BABL_CPU_ACCEL_PPC_ALTIVEC = 0x04000000,
- BABL_CPU_ACCEL_X86_64 = 0x00100000
+ BABL_CPU_ACCEL_PPC_ALTIVEC = 0x00000010,
+
+ /* arm accelerations */
+ BABL_CPU_ACCEL_ARM_NEON = 0x00000020,
+
+ /* x86_64 arch */
+ BABL_CPU_ACCEL_X86_64 = 0x00000040
} BablCpuAccelFlags;
+
BablCpuAccelFlags babl_cpu_accel_get_support (void);
void babl_cpu_accel_set_use (unsigned int use);
diff --git a/babl/babl-extension.c b/babl/babl-extension.c
index 41edb8e..0d36eef 100644
--- a/babl/babl-extension.c
+++ b/babl/babl-extension.c
@@ -31,8 +31,9 @@
#include "babl-internal.h"
#include "babl-db.h"
#include "babl-base.h"
+
#include <string.h>
-#include <stdarg.h>
+
static Babl *babl_extension_current_extender = NULL;
@@ -107,7 +108,9 @@ babl_extension_base (void)
if (ret != babl)
babl_free (babl);
else
+ {
babl_base_init ();
+ }
babl = ret;
}
babl_set_extender (NULL);
@@ -172,7 +175,22 @@ dlsym (HLIB handle,
#include <windows.h>
#define HLIB HINSTANCE
-#define dlopen(a, b) LoadLibrary (a)
+static HLIB
+LoadLibraryWrap (const char *filename)
+{
+ wchar_t *filename_utf16 = babl_convert_utf8_to_utf16 (filename);
+ HLIB module = NULL;
+
+ if (!filename_utf16)
+ return NULL;
+
+ module = LoadLibraryW (filename_utf16);
+
+ babl_free (filename_utf16);
+ return module;
+}
+
+#define dlopen(a, b) LoadLibraryWrap (a)
#define dlsym(l, s) GetProcAddress (l, s)
#define dlclose(l) FreeLibrary (l)
#define dlerror() GetLastError ()
@@ -242,39 +260,53 @@ babl_extension_load (const char *path)
}
}
+struct dir_foreach_ctx
+{
+ const char **exclusion_patterns;
+};
+
static void
-babl_extension_load_dir (const char *base_path)
+dir_foreach (const char *base_path,
+ const char *entry,
+ void *user_data)
{
- DIR *dir;
+ struct dir_foreach_ctx *ctx = (struct dir_foreach_ctx*) user_data;
- if ((dir = opendir (base_path)))
+ if (entry[0] != '.')
{
- struct dirent *dentry;
+ char *path = NULL;
+ char *extension;
+
+ path = babl_strcat (path, base_path);
+ path = babl_strcat (path, BABL_DIR_SEPARATOR);
+ path = babl_strcat (path, entry);
- while ((dentry = readdir (dir)) != NULL)
+ if ((extension = strrchr (entry, '.')) != NULL &&
+ !strcmp (extension, SHREXT))
{
- if (dentry->d_name[0] != '.')
- {
- char *path = NULL;
- char *extension;
-
- path = babl_strcat (path, base_path);
- path = babl_strcat (path, BABL_DIR_SEPARATOR);
- path = babl_strcat (path, dentry->d_name);
-
- if ((extension = strrchr (dentry->d_name, '.')) != NULL &&
- !strcmp (extension, SHREXT))
- {
- babl_extension_load (path);
- }
-
- babl_free (path);
- }
+ int excluded = 0;
+ for (int i = 0; ctx->exclusion_patterns[i]; i++)
+ if (strstr (path, ctx->exclusion_patterns[i]))
+ excluded = 1;
+ if (!excluded)
+ babl_extension_load (path);
}
- closedir (dir);
+
+ babl_free (path);
}
}
+static void
+babl_extension_load_dir (const char *base_path,
+ const char **exclusion_patterns)
+{
+ struct dir_foreach_ctx ctx;
+
+ ctx.exclusion_patterns = exclusion_patterns;
+
+ _babl_dir_foreach (base_path, dir_foreach, &ctx);
+}
+
static char *
expand_path (char *path)
{
@@ -312,7 +344,8 @@ expand_path (char *path)
/* parse the provided colon seperated list of paths to search
*/
void
-babl_extension_load_dir_list (const char *dir_list)
+babl_extension_load_dir_list (const char *dir_list,
+ const char **exclusion_patterns)
{
int eos = 0;
const char *src;
@@ -329,13 +362,13 @@ babl_extension_load_dir_list (const char *dir_list)
{
case '\0':
eos = 1;
- /* don't break here, the path needs to be processed */
-
+ // the path needs to be processed.
+ // fall through
case BABL_PATH_SEPARATOR:
{
char *expanded_path = expand_path (path);
if (expanded_path) {
- babl_extension_load_dir (expanded_path);
+ babl_extension_load_dir (expanded_path, exclusion_patterns);
babl_free (expanded_path);
}
}
diff --git a/babl/babl-extension.h b/babl/babl-extension.h
index 82e1d7e..50fb731 100644
--- a/babl/babl-extension.h
+++ b/babl/babl-extension.h
@@ -28,7 +28,8 @@ BABL_CLASS_DECLARE (extension);
*/
const Babl * babl_extension (const char *name);
-void babl_extension_load_dir_list (const char *dir_list);
+void babl_extension_load_dir_list (const char *dir_list,
+ const char **exclusion_patterns);
typedef struct
{
diff --git a/babl/babl-fish-path.c b/babl/babl-fish-path.c
index b0396db..712f57a 100644
--- a/babl/babl-fish-path.c
+++ b/babl/babl-fish-path.c
@@ -32,8 +32,523 @@
#define MIN(a, b) (((a) > (b)) ? (b) : (a))
#endif
+static int enable_lut = 0;
+
+typedef struct GcContext {
+ long time;
+} GcContext;
+
+static float lut_unused_minutes_limit = 5.0;
+
+static int lut_info_level = 0;
+
+#define _LUT_LOG(level, ...) do{\
+ if (level <= lut_info_level)\
+ fprintf (stdout, __VA_ARGS__);\
+ fflush(NULL);\
+ }while(0)
+#define LUT_LOG(...) _LUT_LOG(1, __VA_ARGS__)
+#define LUT_INFO(...) _LUT_LOG(2, __VA_ARGS__)
+#define LUT_DETAIL(...) _LUT_LOG(3, __VA_ARGS__)
+
+static int gc_fishes (Babl *babl, void *userdata)
+{
+ GcContext *context = userdata;
+ if (babl->class_type == BABL_FISH_PATH)
+ {
+ if (babl->fish_path.u8_lut)
+ {
+ if (context->time - babl->fish_path.last_lut_use >
+ 1000 * 1000 * 60 * lut_unused_minutes_limit)
+ {
+ void *lut =babl->fish_path.u8_lut;
+ BABL(babl)->fish_path.u8_lut = NULL;
+ free (lut);
+ BABL(babl)->fish.pixels = 0;
+ LUT_LOG("freeing LUT %s to %s unused for >%.1f minutes\n",
+ babl_get_name (babl->conversion.source),
+ babl_get_name (babl->conversion.destination),
+ lut_unused_minutes_limit);
+ }
+ else if (lut_info_level >=4)
+ {
+ LUT_DETAIL("active LUT %s to %s %8li pixels last used %.1f minutes ago\n",
+ babl_get_name (babl->conversion.source),
+ babl_get_name (babl->conversion.destination),
+ babl->fish.pixels,
+ (context->time - babl->fish_path.last_lut_use)/1000.0/1000.0/60.0);
+ }
+ }
+ else if (lut_info_level >= 4 && babl->fish.pixels)
+ {
+ if (babl->fish_path.is_u8_color_conv)
+ LUT_DETAIL("potential LUT %s to %s %8li pixels\n",
+ babl_get_name (babl->conversion.source),
+ babl_get_name (babl->conversion.destination),
+ babl->fish.pixels);
+ else if (lut_info_level >=5)
+ LUT_DETAIL("%i step path %s to %s %8li pixels\n",
+ babl->fish_path.conversion_list->count,
+ babl_get_name (babl->conversion.source),
+ babl_get_name (babl->conversion.destination),
+ babl->fish.pixels);
+ }
+ babl->fish.pixels /= 2; // decay pixel count// this is enough that we *will* reach 0
+ }
+ return 0;
+}
+
+static void
+babl_gc_fishes (void)
+{
+ GcContext context;
+ context.time = babl_ticks ();
+ if (lut_info_level >= 5)
+ {
+ fprintf (stdout, "\e[H\e[2J");
+ }
+ babl_fish_class_for_each (gc_fishes, &context);
+}
+
+static long babl_conv_counter = 0;
+
+void
+babl_gc (void)
+{
+ if (babl_conv_counter > 1000 * 1000 * 10) // run gc every 10 megapixels
+ {
+ babl_conv_counter = 0;
+ babl_gc_fishes ();
+ //malloc_trim (0);
+ // is responsibility of higher layers
+ }
+}
+
+#define BABL_LIKELY(x) __builtin_expect(!!(x), 1)
+#define BABL_UNLIKELY(x) __builtin_expect(!!(x), 0)
+
+static float timings[256] = {0,};
+
+#define BPP_4ASSOCIATED 14
+
+static inline int _do_lut (uint32_t *lut,
+ int source_bpp,
+ int dest_bpp,
+ const void *__restrict__ source,
+ void *__restrict__ destination,
+ long n)
+{
+ if (source_bpp == BPP_4ASSOCIATED && dest_bpp == 4)
+ {
+ uint32_t *src = (uint32_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ uint32_t col = *src++;
+ uint8_t *rgba=(uint8_t*)&col;
+ uint8_t oalpha = rgba[3];
+ if (oalpha==0)
+ {
+ *dst++ = 0;
+ }
+ else
+ {
+ uint32_t col_opaque = col;
+ uint8_t *rgbaB=(uint8_t*)&col_opaque;
+ uint32_t ralpha = 0;
+ ralpha = (256*255)/oalpha;
+ rgbaB[0] = (rgba[0]*ralpha)>>8;
+ rgbaB[1] = (rgba[1]*ralpha)>>8;
+ rgbaB[2] = (rgba[2]*ralpha)>>8;
+ rgbaB[3] = 0;
+ *dst++ = lut[col_opaque] | (oalpha<<24);
+ }
+ }
+ }
+ else if (source_bpp == 4 && dest_bpp == 16)
+ {
+ uint32_t *src = (uint32_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ uint32_t col = *src++;
+ uint32_t lut_offset = col & 0xffffff;
+ float alpha = (col>>24)/255.0f;
+
+ *dst++ = lut[lut_offset*4+0];
+ *dst++ = lut[lut_offset*4+1];
+ *dst++ = lut[lut_offset*4+2];
+ ((float*)(dst))[0] = alpha;
+ dst++;
+ }
+ }
+ else if (source_bpp == 4 && dest_bpp == 8)
+ {
+ uint32_t *src = (uint32_t*)source;
+ uint16_t *dst = (uint16_t*)destination;
+ uint16_t *lut16 = (uint16_t*)lut;
+ while (n--)
+ {
+ uint32_t col = *src++;
+ uint32_t lut_offset = col & 0xffffff;
+ uint16_t alpha = (col>>24) << 8;
+
+ dst[0] = lut16[lut_offset*2+0];
+ dst[1] = lut16[lut_offset*2+1];
+ dst[2] = lut16[lut_offset*2+2];
+ dst[3] = alpha;
+ dst+=4;
+ }
+ }
+ else if (source_bpp == 2 && dest_bpp == 16)
+ {
+ uint16_t *src = (uint16_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ uint32_t col = *src++;
+ *dst++ = lut[col*4+0];
+ *dst++ = lut[col*4+1];
+ *dst++ = lut[col*4+2];
+ *dst++ = lut[col*4+3];
+ }
+ }
+ else if (source_bpp == 4 && dest_bpp == 4)
+ {
+ uint32_t *src = (uint32_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ uint32_t col = *src++;
+ *dst = (col & 0xff000000) | lut[col & 0xffffff];
+ dst++;
+ }
+ }
+ else if (source_bpp == 2 && dest_bpp == 4)
+ {
+ uint16_t *src = (uint16_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ *dst = lut[*src++];
+ dst++;
+ }
+ }
+ else if (source_bpp == 2 && dest_bpp == 2)
+ {
+ uint16_t *src = (uint16_t*)source;
+ uint16_t *dst = (uint16_t*)destination;
+ uint16_t *lut16 = (uint16_t*)lut;
+ while (n--)
+ {
+ *dst = lut16[*src++];
+ dst++;
+ }
+ }
+ else if (source_bpp == 1 && dest_bpp == 4)
+ {
+ uint8_t *src = (uint8_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ *dst = lut[*src++];
+ dst++;
+ }
+ }
+ else if (source_bpp == 3 && dest_bpp == 3)
+ {
+ uint8_t *src = (uint8_t*)source;
+ uint8_t *dst = (uint8_t*)destination;
+ while (n--)
+ {
+ uint32_t col = src[0]*256*256+src[1]*256+src[2];
+ uint32_t val = lut[col];
+ dst[2]=(val >> 16) & 0xff;
+ dst[1]=(val >> 8) & 0xff;
+ dst[0]=val & 0xff;
+ dst+=3;
+ src+=3;
+ }
+ }
+ else if (source_bpp == 3 && dest_bpp == 4)
+ {
+ uint8_t *src = (uint8_t*)source;
+ uint32_t *dst = (uint32_t*)destination;
+ while (n--)
+ {
+ *dst = lut[src[0]*256*256+src[1]*256+src[2]];
+ dst++;
+ src+=3;
+ }
+ }
+ else
+ {
+ return 0;
+ }
+ return 1;
+}
+
+void babl_test_lut (uint32_t *lut,
+ int source_bpp,
+ int dest_bpp,
+ void *__restrict__ source,
+ void *__restrict__ dest,
+ long count);
+void babl_test_lut (uint32_t *lut,
+ int source_bpp,
+ int dest_bpp,
+ void *__restrict__ source,
+ void *__restrict__ dest,
+ long count)
+{
+ _do_lut (lut, source_bpp, dest_bpp, source, dest, count);
+}
+
+static inline float lut_timing_for (int source_bpp, int dest_bpp)
+{
+ return timings[source_bpp * 16 + dest_bpp];
+}
+
+static void measure_timings(void)
+{
+ int num_pixels = babl_get_num_path_test_pixels () * 1000;
+ int pairs[][2]={{4,4},{BPP_4ASSOCIATED,4},{4,8},{3,4},{3,3},{2,4},{2,2},{1,4},{2,16},{4,16}};
+ uint32_t *lut = malloc (256 * 256 * 256 * 16);
+ uint32_t *src = malloc (num_pixels * 16);
+ uint32_t *dst = malloc (num_pixels * 16);
+
+ memset (lut, 11, 256 * 256 * 256 *16);
+ memset (src, 12, num_pixels * 16);
+
+ if (getenv ("BABL_LUT_INFO"))
+ {
+ lut_info_level = atoi (getenv ("BABL_LUT_INFO"));
+ }
+ if (getenv ("BABL_LUT_UNUSED_LIMIT"))
+ {
+ lut_unused_minutes_limit = atof (getenv ("BABL_LUT_UNUSED_LIMIT"));
+ }
+
+ LUT_LOG("BABL_LUT_UNUSED_LIMIT=%.1f\n", lut_unused_minutes_limit);
+
+ LUT_LOG("measuring lut timings \n");
+ for (size_t p = 0; p < sizeof (pairs)/sizeof(pairs[0]);p++)
+ {
+ int source_bpp = pairs[p][0];
+ int dest_bpp = pairs[p][1];
+ long start,end;
+ start = babl_ticks ();
+ babl_test_lut (lut, source_bpp, dest_bpp, src, dst, num_pixels);
+
+ end = babl_ticks ();
+ timings[source_bpp * 16 + dest_bpp] = (end-start)/1000.0;
+ LUT_LOG (" %ibpp to %ibpp: %.2f\n", source_bpp, dest_bpp,
+ timings[source_bpp * 16 + dest_bpp]
+ );
+ }
+ free (lut);
+ free (src);
+ free (dst);
+}
+
+static inline void
+process_conversion_path (BablList *path,
+ const void *source_buffer,
+ int source_bpp,
+ void *destination_buffer,
+ int dest_bpp,
+ long n);
+
+static inline int babl_fish_lut_process_maybe (const Babl *babl,
+ const char *source,
+ char *destination,
+ long n,
+ void *data)
+{
+ int source_bpp = babl->fish_path.source_bpp;
+ int dest_bpp = babl->fish_path.dest_bpp;
+ uint32_t *lut = (uint32_t*)babl->fish_path.u8_lut;
+
+
+ if (BABL_UNLIKELY(!lut && babl->fish.pixels >= 128 * 256))
+ {
+ LUT_LOG("generating LUT for %s to %s\n",
+ babl_get_name (babl->conversion.source),
+ babl_get_name (babl->conversion.destination));
+ if (source_bpp ==4 && dest_bpp == 4)
+ {
+ lut = malloc (256 * 256 * 256 * 4);
+ for (int o = 0; o < 256 * 256 * 256; o++)
+ lut[o] = o | 0xff000000;
+ process_conversion_path (babl->fish_path.conversion_list,
+ lut, 4,
+ lut, 4,
+ 256*256*256);
+ for (int o = 0; o < 256 * 256 * 256; o++)
+ lut[o] = lut[o] & 0x00ffffff;
+
+ }
+ else if (source_bpp == 4 && dest_bpp == 16)
+ {
+ uint32_t *temp_lut = malloc (256 * 256 * 256 * 4);
+ lut = malloc (256 * 256 * 256 * 16);
+ for (int o = 0; o < 256 * 256 * 256; o++)
+ temp_lut[o] = o | 0xff000000;
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 4,
+ lut, 16,
+ 256*256*256);
+ free (temp_lut);
+ }
+ else if (source_bpp == 4 && dest_bpp == 8)
+ {
+ uint32_t *temp_lut = malloc (256 * 256 * 256 * 4);
+ lut = malloc (256 * 256 * 256 * 8);
+ for (int o = 0; o < 256 * 256 * 256; o++)
+ temp_lut[o] = o | 0xff000000;
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 4,
+ lut, 8,
+ 256*256*256);
+ free (temp_lut);
+ }
+ else if (source_bpp == 3 && dest_bpp == 3)
+ {
+ uint8_t *temp_lut = malloc (256 * 256 * 256 * 3);
+ uint8_t *temp_lut2 = malloc (256 * 256 * 256 * 3);
+ int o = 0;
+ lut = malloc (256 * 256 * 256 * 4);
+ for (int r = 0; r < 256; r++)
+ for (int g = 0; g < 256; g++)
+ for (int b = 0; b < 256; b++, o++)
+ {
+ temp_lut[o*3+0]=r;
+ temp_lut[o*3+1]=g;
+ temp_lut[o*3+2]=b;
+ }
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 3,
+ temp_lut2, 3,
+ 256*256*256);
+ babl_process (babl_fish (babl_format ("R'G'B' u8"), babl_format ("R'G'B'A u8")),
+ temp_lut2, lut, 256*256*256);
+ for (int o = 0; o < 256 * 256 * 256; o++)
+ lut[o] = lut[o] & 0x00ffffff;
+ free (temp_lut);
+ free (temp_lut2);
+ }
+ else if (source_bpp == 3 && dest_bpp == 4)
+ {
+ uint8_t *temp_lut = malloc (256 * 256 * 256 * 3);
+ int o = 0;
+ lut = malloc (256 * 256 * 256 * 4);
+ for (int r = 0; r < 256; r++)
+ for (int g = 0; g < 256; g++)
+ for (int b = 0; b < 256; b++, o++)
+ {
+ temp_lut[o*3+0]=r;
+ temp_lut[o*3+1]=g;
+ temp_lut[o*3+2]=b;
+ }
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 3,
+ lut, 4,
+ 256*256*256);
+ free (temp_lut);
+ }
+ else if (source_bpp == 2 && dest_bpp == 2)
+ {
+ uint16_t *temp_lut = malloc (256 * 256 * 2);
+ lut = malloc (256 * 256 * 4);
+ for (int o = 0; o < 256*256; o++)
+ {
+ temp_lut[o]=o;
+ }
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 2,
+ lut, 2,
+ 256*256);
+ free (temp_lut);
+ }
+ else if (source_bpp == 2 && dest_bpp == 4)
+ {
+ uint16_t *temp_lut = malloc (256 * 256 * 2);
+ lut = malloc (256 * 256 * 4);
+ for (int o = 0; o < 256*256; o++)
+ {
+ temp_lut[o]=o;
+ }
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 2,
+ lut, 4,
+ 256*256);
+ free (temp_lut);
+ }
+ else if (source_bpp == 2 && dest_bpp == 16)
+ {
+ uint16_t *temp_lut = malloc (256 * 256 * 2);
+ lut = malloc (256 * 256 * 16);
+ for (int o = 0; o < 256*256; o++)
+ {
+ temp_lut[o]=o;
+ }
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 2,
+ lut, 16,
+ 256*256);
+ free (temp_lut);
+ }
+ else if (source_bpp == 1 && dest_bpp == 4)
+ {
+ uint8_t *temp_lut = malloc (256);
+ lut = malloc (256 * 4);
+ for (int o = 0; o < 256; o++)
+ {
+ temp_lut[o]=o;
+ }
+ process_conversion_path (babl->fish_path.conversion_list,
+ temp_lut, 1,
+ lut, 4,
+ 256);
+ free (temp_lut);
+ }
+
+ if (babl->fish_path.u8_lut == NULL)
+ {
+ (BABL(babl)->fish_path.u8_lut) = lut;
+ // XXX need memory barrier?
+ if ((BABL(babl)->fish_path.u8_lut) != lut)
+ {
+ free (lut);
+ lut = babl->fish_path.u8_lut;
+ }
+ }
+ else
+ {
+ free (lut);
+ lut = babl->fish_path.u8_lut;
+ }
+ }
+
+ if (lut)
+ {
+ if (source_bpp == 4 &&
+ ((babl->conversion.source->format.model->flags &
+ BABL_MODEL_FLAG_ASSOCIATED)!=0))
+ source_bpp = BPP_4ASSOCIATED;
+
+ if (_do_lut (lut, source_bpp, dest_bpp, source, destination, n))
+ {
+ BABL(babl)->fish_path.last_lut_use = babl_ticks ();
+ return 1;
+ }
+ }
+ return 0;
+}
+
+
+
#define MAX_BUFFER_SIZE 512
-#define ITERATIONS 4
int babl_in_fish_path = 0;
@@ -100,7 +615,6 @@ _babl_fish_create_name (char *buf,
static int max_path_length (void);
static int debug_conversions = 0;
-int _babl_instrument = 0;
double
_babl_legal_error (void)
@@ -123,11 +637,19 @@ _babl_legal_error (void)
else
debug_conversions = 0;
- env = getenv ("BABL_INSTRUMENT");
+ env = getenv ("BABL_LUT");
if (env && env[0] != '\0')
- _babl_instrument = 1;
+ enable_lut = atoi(getenv("BABL_LUT"));
else
- _babl_instrument = 0;
+ enable_lut = 1;
+
+ {
+ const uint32_t u32 = 1;
+ if ( *((char*)&u32) == 0)
+ { /* disable use of LUTs if we are running on big endian */
+ enable_lut = 0;
+ }
+ }
return error;
}
@@ -145,9 +667,9 @@ max_path_length (void)
if (env)
max_length = atoi (env);
else
- max_length = 2; /* reducing this number makes finding short fishes much
+ max_length = 3; /* reducing this number makes finding short fishes much
faster - even if we lose out on some of the fast
- bigger fish, the fishes we can get with a max_length of 2
+ bigger fish, the fishes we can get with a max_length of 3
is actually 5, since we deepen the search to that
depth if none are found within two steps in the
initial search.
@@ -317,6 +839,9 @@ int
_babl_fish_path_destroy (void *data)
{
Babl *babl=data;
+ if (babl->fish_path.u8_lut)
+ free (babl->fish_path.u8_lut);
+ babl->fish_path.u8_lut = NULL;
if (babl->fish_path.conversion_list)
babl_free (babl->fish_path.conversion_list);
babl->fish_path.conversion_list = NULL;
@@ -406,6 +931,7 @@ alias_conversion (Babl *babl,
babl_remodel_with_space (
(void*)conv->destination, (void*)space),
"linear", conv->function.linear,
+ "data", conv->data,
NULL);
break;
case BABL_CONVERSION_PLANAR:
@@ -415,6 +941,7 @@ alias_conversion (Babl *babl,
babl_remodel_with_space (
(void*)conv->destination, (void*)space),
"planar", conv->function.planar,
+ "data", conv->data,
NULL);
break;
case BABL_CONVERSION_PLANE:
@@ -424,6 +951,7 @@ alias_conversion (Babl *babl,
babl_remodel_with_space (
(void*)conv->destination, (void*)space),
"plane", conv->function.plane,
+ "data", conv->data,
NULL);
break;
default:
@@ -469,6 +997,92 @@ _babl_fish_prepare_bpp (Babl *babl)
default:
babl_log ("-eeek{%i}\n", babl_dest->instance.class_type - BABL_MAGIC);
}
+
+ if (enable_lut)
+ {
+ int source_bpp = babl->fish_path.source_bpp;
+ int dest_bpp = babl->fish_path.dest_bpp;
+ const Babl *source_type = babl_format_get_type (babl_source,
+ babl_format_get_n_components (babl_source) - 1);
+ const Babl *dest_type = babl_format_get_type (babl_dest,
+ babl_format_get_n_components (babl_dest) - 1);
+
+ int src_not_associated = ((babl->conversion.source->format.model->flags &
+ BABL_MODEL_FLAG_ASSOCIATED)==0);
+ int dest_not_associated = ((babl->conversion.destination->format.model->flags &
+ BABL_MODEL_FLAG_ASSOCIATED)==0);
+ if (
+ (babl->conversion.source->format.type[0]->bits < 32)
+
+ && ( ( source_bpp == 2
+ && dest_bpp == 16)
+
+ ||( source_bpp == 4
+ && dest_bpp == 16
+ && source_type == babl_type_from_id (BABL_U8)
+ && dest_type == babl_type_from_id (BABL_FLOAT)
+ && src_not_associated
+ && dest_not_associated)
+
+ ||( source_bpp == 4
+ && dest_bpp == 4
+ && dest_type == source_type
+ && dest_not_associated)
+
+ ||( source_bpp == 4
+ && dest_bpp == 8
+ && source_type == babl_type_from_id (BABL_U8)
+ && dest_type == babl_type_from_id (BABL_U16)
+ && src_not_associated
+ && dest_not_associated)
+
+ ||( source_bpp == 3
+ && dest_bpp == 4)
+
+ ||( source_bpp == 2
+ && dest_bpp == 4)
+
+ ||( source_bpp == 2
+ && dest_bpp == 2)
+
+ ||( source_bpp == 1
+ && dest_bpp == 4)
+
+ ||( source_bpp == 3
+ && dest_bpp == 3)
+ )
+ )
+ {
+ // as long as the highest 8bit of the 32bit of a 4 byte input is ignored
+ // (alpha) - and it is not an associated color model. A 24 bit LUT provides
+ // exact data.
+ // Note that we can only copy alpha from source to complete when
+ // types are matching expectations - the source_bpp/dest_bpp pairs have
+ // currently have built-in expectation for what type alpha is filled in
+ {
+ static int measured_timings = 0;
+ float scaling = 10.0;
+ if (!measured_timings) measure_timings ();
+ measured_timings = 1;
+ LUT_LOG ("%sLUT for %s to %s %.2f%s%.2f\n",
+
+ ((lut_timing_for (source_bpp, dest_bpp) * scaling) <
+ babl->fish_path.cost)?"possible ":"no ",
+
+ babl_get_name (babl->conversion.source),
+ babl_get_name (babl->conversion.destination),
+ (lut_timing_for (source_bpp, dest_bpp) * scaling),
+ ((lut_timing_for (source_bpp, dest_bpp) * scaling) <
+ babl->fish_path.cost)?" < ":" > ",
+ babl->fish_path.cost);
+ if ((lut_timing_for (source_bpp, dest_bpp) * scaling) <
+ babl->fish_path.cost)
+ {
+ babl->fish_path.is_u8_color_conv = 1;
+ }
+ }
+ }
+ }
}
void
@@ -549,6 +1163,7 @@ babl_fish_path2 (const Babl *source,
static const Babl *run_once[512]={NULL};
int i;
int done = 0;
+
for (i = 0; run_once[i]; i++)
{
if (run_once[i] == source->format.space)
@@ -579,7 +1194,6 @@ babl_fish_path2 (const Babl *source,
{
babl_conversion_class_for_each (show_item, (void*)source->format.space);
}
-
}
babl = babl_calloc (1, sizeof (BablFishPath) +
@@ -598,10 +1212,11 @@ babl_fish_path2 (const Babl *source,
babl->fish_path.conversion_list = babl_list_init_with_size (BABL_HARD_MAX_PATH_LENGTH);
+
{
PathContext pc;
int start_depth = max_path_length ();
- int end_depth = start_depth + 2 + ((destination->format.space != sRGB)?1:0);
+ int end_depth = start_depth + 1 + ((destination->format.space != sRGB)?1:0);
end_depth = MIN(end_depth, BABL_HARD_MAX_PATH_LENGTH);
pc.current_path = babl_list_init_with_size (BABL_HARD_MAX_PATH_LENGTH);
@@ -649,6 +1264,7 @@ babl_fish_path2 (const Babl *source,
}
_babl_fish_prepare_bpp (babl);
+
_babl_fish_rig_dispatch (babl);
/* Since there is not an already registered instance by the required
* name, inserting newly created class into database.
@@ -701,6 +1317,18 @@ babl_fish_path_process (const Babl *babl,
long n,
void *data)
{
+ BABL(babl)->fish.pixels += n;
+ if (babl->fish_path.is_u8_color_conv)
+ {
+ if (babl_fish_lut_process_maybe (babl,
+ source, destination, n,
+ data))
+ return;
+ }
+ else
+ {
+ babl_conv_counter+=n;
+ }
process_conversion_path (babl->fish_path.conversion_list,
source,
babl->fish_path.source_bpp,
@@ -787,8 +1415,6 @@ _babl_process (const Babl *cbabl,
{
Babl *babl = (void*)cbabl;
babl->fish.dispatch (babl, source, destination, n, *babl->fish.data);
- if (_babl_instrument)
- babl->fish.pixels += n;
return n;
}
@@ -820,8 +1446,6 @@ babl_process_rows (const Babl *fish,
if (n <= 0)
return 0;
- if (_babl_instrument)
- babl->fish.pixels += n * rows;
for (row = 0; row < rows; row++)
{
babl->fish.dispatch (babl, (void*)src, (void*)dst, n, *babl->fish.data);
@@ -835,7 +1459,7 @@ babl_process_rows (const Babl *fish,
#include <stdint.h>
#define BABL_ALIGN 16
-static void inline *align_16 (unsigned char *ret)
+static inline void *align_16 (unsigned char *ret)
{
int offset = BABL_ALIGN - ((uintptr_t) ret) % BABL_ALIGN;
ret = ret + offset;
diff --git a/babl/babl-fish-reference.c b/babl/babl-fish-reference.c
index a62f32a..2725e3e 100644
--- a/babl/babl-fish-reference.c
+++ b/babl/babl-fish-reference.c
@@ -358,7 +358,6 @@ ncomponent_convert_from_double (BablFormat *destination_fmt,
src_img->stride[0] = 0;
dst_img->data[0] = destination_buf;
- dst_img->type[0] = (BablType *) babl_type_from_id (BABL_DOUBLE);
dst_img->pitch[0] = destination_fmt->type[0]->bits/8;
dst_img->stride[0] = 0;
@@ -480,7 +479,6 @@ ncomponent_convert_from_float (BablFormat *source_fmt,
src_img->stride[0] = 0;
dst_img->data[0] = destination_buf;
- dst_img->type[0] = (BablType *) babl_type_from_id (BABL_FLOAT);
dst_img->pitch[0] = destination_fmt->type[0]->bits/8;
dst_img->stride[0] = 0;
diff --git a/babl/babl-fish.c b/babl/babl-fish.c
index ce22b6b..06d7961 100644
--- a/babl/babl-fish.c
+++ b/babl/babl-fish.c
@@ -253,6 +253,7 @@ babl_fish (const void *source,
* we will search through the fish database for reference fish
* to handle the memcpy */
babl_hash_table_find (id_htable, hashval, find_memcpy_fish, (void *) &ffish);
+ babl_mutex_lock (babl_fish_mutex);
}
else
{
@@ -359,4 +360,10 @@ babl_fish (const void *source,
}
}
+
+BablFishProcess babl_fish_get_process (const Babl *babl)
+{
+ return babl->fish.dispatch;
+}
+
BABL_CLASS_MINIMAL_IMPLEMENT (fish);
diff --git a/babl/babl-fish.h b/babl/babl-fish.h
index 35382f0..0ad9101 100644
--- a/babl/babl-fish.h
+++ b/babl/babl-fish.h
@@ -69,6 +69,9 @@ typedef struct
double cost; /* number of ticks *10 + chain_length */
int source_bpp;
int dest_bpp;
+ unsigned int is_u8_color_conv:1; // keep track of count, and make
+ uint32_t *u8_lut;
+ long last_lut_use;
BablList *conversion_list;
} BablFishPath;
diff --git a/babl/babl-format.c b/babl/babl-format.c
index 2e4e3d7..cbcc880 100644
--- a/babl/babl-format.c
+++ b/babl/babl-format.c
@@ -140,8 +140,9 @@ format_new_from_format_with_space (const Babl *format,
{
Babl *ret;
char new_name[256];
- snprintf (new_name, sizeof (new_name), "%s-%s", babl_get_name ((void*)format),
+ snprintf (new_name, sizeof (new_name)-1, "%s-%s", babl_get_name ((void*)format),
babl_get_name ((void*)space));
+ new_name[255]=0;
ret = babl_db_find (babl_format_db(), new_name);
if (ret)
return ret;
@@ -346,7 +347,7 @@ babl_format_new (const void *first_arg,
int components = 0;
BablModel *model = NULL;
const Babl *space = babl_space ("sRGB");
- const char *doc = NULL;
+ char *doc = NULL;
BablComponent *component [BABL_MAX_COMPONENTS];
BablSampling *sampling [BABL_MAX_COMPONENTS];
const BablType*type [BABL_MAX_COMPONENTS];
@@ -468,16 +469,18 @@ babl_format_new (const void *first_arg,
va_end (varg);
if (!name)
- name = create_name (model, components, component, type);
+ {
+ name = create_name (model, components, component, type);
- if (space != babl_space ("sRGB"))
- {
- char *new_name = babl_malloc (strlen (name) +
- strlen (babl_get_name ((Babl*)space)) + 1);
- sprintf (new_name, "%s-%s", name, babl_get_name ((Babl*)space));
- babl_free (name);
- name = new_name;
- }
+ if (space != babl_space ("sRGB"))
+ {
+ char *new_name = babl_malloc (strlen (name) +
+ strlen (babl_get_name ((Babl*)space)) + 1);
+ sprintf (new_name, "%s-%s", name, babl_get_name ((Babl*)space));
+ babl_free (name);
+ name = new_name;
+ }
+ }
if (!model)
{
@@ -508,6 +511,7 @@ babl_format_new (const void *first_arg,
"with different content!", name);
babl_free (name);
+ babl_free (doc);
return babl;
}
diff --git a/babl/babl-icc.c b/babl/babl-icc.c
index a21888f..38e382a 100644
--- a/babl/babl-icc.c
+++ b/babl/babl-icc.c
@@ -322,6 +322,11 @@ read_sign (ICC *state,
int offset)
{
sign_t ret;
+ if (offset < 0 || offset > state->length - 4)
+ {
+ for (int i = 0; i < 5; i ++) ret.str[0]=0;
+ return ret;
+ }
ret.str[0]=icc_read (u8, offset);
ret.str[1]=icc_read (u8, offset + 1);
ret.str[2]=icc_read (u8, offset + 2);
@@ -356,10 +361,23 @@ icc_tag (ICC *state,
sign_t sign = icc_read (sign, TAG_COUNT_OFF + 4 + 12 * t);
if (!strcmp (sign.str, tag))
{
+ int off = icc_read (u32, TAG_COUNT_OFF + 4 + 12* t + 4);
+ int len = icc_read (u32, TAG_COUNT_OFF + 4 + 12* t + 4*2);
+
+ if (off + len > state->length || off < 0)
+ {
+ if (offset)
+ *offset = 0;
+ if (el_length)
+ *el_length = 0;
+ return 0; // broken input
+ }
+
if (offset)
- *offset = icc_read (u32, TAG_COUNT_OFF + 4 + 12* t + 4);
+ *offset = off;
if (el_length)
- *el_length = icc_read (u32, TAG_COUNT_OFF + 4 + 12* t + 4*2);
+ *el_length = len;
+
return 1;
}
}
@@ -384,18 +402,36 @@ babl_trc_from_icc (ICC *state,
g = icc_read (s15f16, offset + 12 + 4 * 0);
return babl_trc_gamma (g);
break;
+ case 1:
+ {
+ float a,b,c;
+ g = icc_read (s15f16, offset + 12 + 4 * 0);
+ a = icc_read (s15f16, offset + 12 + 4 * 1);
+ b = icc_read (s15f16, offset + 12 + 4 * 2);
+ c = 0;
+ return babl_trc_formula_cie (g, a, b, c);
+ }
+ case 2:
+ {
+ float a,b,c;
+ g = icc_read (s15f16, offset + 12 + 4 * 0);
+ a = icc_read (s15f16, offset + 12 + 4 * 1);
+ b = icc_read (s15f16, offset + 12 + 4 * 2);
+ c = icc_read (s15f16, offset + 12 + 4 * 3);
+ return babl_trc_formula_cie (g, a, b, c);
+ }
case 3:
{
- float a,b,c,d;
+ float a,b,c,d,e,f;
g = icc_read (s15f16, offset + 12 + 4 * 0);
a = icc_read (s15f16, offset + 12 + 4 * 1);
b = icc_read (s15f16, offset + 12 + 4 * 2);
c = icc_read (s15f16, offset + 12 + 4 * 3);
d = icc_read (s15f16, offset + 12 + 4 * 4);
- //fprintf (stderr, "%f %f %f %f %f\n", g, a, b, c, d);
- return babl_trc_formula_srgb (g, a, b, c, d);
+ e = 0.0f;
+ f = 0.0f;
+ return babl_trc_formula_srgb (g, a, b, c, d, e, f);
}
- break;
case 4:
{
float a,b,c,d,e,f;
@@ -406,15 +442,8 @@ babl_trc_from_icc (ICC *state,
d = icc_read (s15f16, offset + 12 + 4 * 4);
e = icc_read (s15f16, offset + 12 + 4 * 5);
f = icc_read (s15f16, offset + 12 + 4 * 6);
- fprintf (stderr, "%f %f %f %f %f %f %f\n",
- g, a, b, c, d, e, f);
- {
- fprintf (stderr, "unhandled parametric sRGB formula TRC type %i\n", function_type);
- *error = "unhandled sRGB formula like TRC";
- return babl_trc_gamma (2.2);
- }
- }
- break;
+ return babl_trc_formula_srgb (g, a, b, c, d, e, f);
+ }
default:
*error = "unhandled parametric TRC";
fprintf (stderr, "unhandled parametric TRC type %i\n", function_type);
@@ -539,6 +568,8 @@ switch (trc->type)
break;
}
case BABL_TRC_FORMULA_SRGB:
+ // fall through
+ case BABL_TRC_FORMULA_CIE:
{
int lut_size = 512;
if (flags == BABL_ICC_COMPACT_TRC_LUT)
@@ -676,7 +707,6 @@ babl_space_to_icc_rgb (const Babl *babl,
icc_write (u8, state->o + 12 + i, description[i]);
}
-
icc_write (u32, 0, state->no + 0);
length = state->no + 0;
}
@@ -941,6 +971,8 @@ babl_space_from_icc (const char *icc_data,
sign_t profile_class, color_space, pcs;
+ babl_mutex_lock (babl_space_mutex);
+
if (!error) error = &int_err;
*error = NULL;
@@ -956,12 +988,23 @@ babl_space_from_icc (const char *icc_data,
if (!strcmp (color_space.str, "CMYK"))
{
ret = _babl_space_for_lcms (icc_data, icc_length);
+ if (!ret)
+ {
+ babl_mutex_unlock (babl_space_mutex);
+ return NULL;
+ }
if (ret->space.icc_type == BablICCTypeCMYK)
+ {
+ babl_mutex_unlock (babl_space_mutex);
return ret;
+ }
ret->space.icc_length = icc_length;
ret->space.icc_profile = malloc (icc_length);
if (!ret->space.icc_profile)
+ {
+ babl_mutex_unlock (babl_space_mutex);
return NULL;
+ }
memcpy (ret->space.icc_profile, icc_data, icc_length);
#ifdef HAVE_LCMS
@@ -991,25 +1034,24 @@ babl_space_from_icc (const char *icc_data,
// INTENT_PERCEPTUAL,0);//intent & 7, 0);
cmsCloseProfile (ret->space.cmyk.lcms_profile); // XXX keep it open in case of CMYK to CMYK transforms needed?
#endif
+ ret->space.icc_type = BablICCTypeCMYK;
+ babl_mutex_unlock (babl_space_mutex);
return ret;
}
-
-
-
- if (strcmp (color_space.str, "RGB ")
- && strcmp (color_space.str, "GRAY")
- )
+ if (!(!strcmp (color_space.str, "RGB ")||
+ !strcmp (color_space.str, "GRAY")))
{
*error = "not defining RGB, CMYK or GRAY space..";
}
else
- {
- if (strcmp (profile_class.str, "mntr"))
- *error = "not a monitor-class profile";
- if (!strcmp (color_space.str, "GRAY"))
- is_gray = 1;
- }
+ {
+ if (!(!strcmp (profile_class.str, "mntr")||
+ !strcmp (profile_class.str, "scnr")))
+ *error = "not a display or input-class profile";
+ if (!strcmp (color_space.str, "GRAY"))
+ is_gray = 1;
+ }
}
if (!*error)
@@ -1051,10 +1093,10 @@ babl_space_from_icc (const char *icc_data,
}
break;
case BABL_ICC_INTENT_ABSOLUTE_COLORIMETRIC:
- *error = "absolute colormetric not implemented";
+ *error = "absolute colorimetric not implemented";
break;
case BABL_ICC_INTENT_SATURATION:
- *error = "absolute stauration not supported";
+ *error = "saturation not supported";
break;
}
@@ -1097,6 +1139,7 @@ babl_space_from_icc (const char *icc_data,
{
babl_free (state);
+ babl_mutex_unlock (babl_space_mutex);
return NULL;
}
@@ -1114,6 +1157,7 @@ babl_space_from_icc (const char *icc_data,
ret->space.icc_profile = malloc (icc_length);
memcpy (ret->space.icc_profile, icc_data, icc_length);
babl_free (state);
+ babl_mutex_unlock (babl_space_mutex);
return ret;
@@ -1159,6 +1203,7 @@ babl_space_from_icc (const char *icc_data,
*error = "Inconsistent ICC profile detected, profile contains both cLUTs and a matrix with swapped primaries, this likely means it is an intentionally inconsistent Argyll profile is in use; this profile is only capable of high accuracy rendering and does not permit acceleration for interactive previews.";
fprintf (stderr, "babl ICC warning: %s\n", *error);
babl_free (state);
+ babl_mutex_unlock (babl_space_mutex);
return NULL;
}
}
@@ -1168,6 +1213,7 @@ babl_space_from_icc (const char *icc_data,
if (ret)
{
babl_free (state);
+ babl_mutex_unlock (babl_space_mutex);
return ret;
}
@@ -1180,9 +1226,10 @@ babl_space_from_icc (const char *icc_data,
trc_red, trc_green, trc_blue);
babl_free (state);
- ret->space.icc_length = icc_length;
+ ret->space.icc_length = icc_length;
ret->space.icc_profile = malloc (icc_length);
memcpy (ret->space.icc_profile, icc_data, icc_length);
+ babl_mutex_unlock (babl_space_mutex);
return ret;
}
}
@@ -1200,11 +1247,13 @@ babl_space_from_icc (const char *icc_data,
if (phosporant != 0)
{
*error = "unhandled phosporants, please report bug against babl with profile";
+ babl_mutex_unlock (babl_space_mutex);
return NULL;
}
if (channels != 3)
{
*error = "unexpected non 3 count of channels";
+ babl_mutex_unlock (babl_space_mutex);
return NULL;
}
@@ -1234,6 +1283,7 @@ babl_space_from_icc (const char *icc_data,
ret->space.icc_profile = malloc (icc_length);
memcpy (ret->space.icc_profile, icc_data, icc_length);
+ babl_mutex_unlock (babl_space_mutex);
return ret;
}
}
@@ -1241,6 +1291,7 @@ babl_space_from_icc (const char *icc_data,
}
babl_free (state);
+ babl_mutex_unlock (babl_space_mutex);
return NULL;
}
@@ -1467,8 +1518,11 @@ ConvertUTF16toUTF8 (const UTF16 **sourceStart,
}
switch (bytesToWrite) { /* note: everything falls through. */
case 4: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ // fall through
case 3: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ // fall through
case 2: *--target = (UTF8)((ch | byteMark) & byteMask); ch >>= 6;
+ // fall through
case 1: *--target = (UTF8)(ch | firstByteMark[bytesToWrite]);
}
target += bytesToWrite;
diff --git a/babl/babl-internal.c b/babl/babl-internal.c
index f7939a1..072127a 100644
--- a/babl/babl-internal.c
+++ b/babl/babl-internal.c
@@ -84,6 +84,8 @@ BablMutex *babl_format_mutex;
BablMutex *babl_debug_mutex;
#endif
BablMutex *babl_reference_mutex;
+BablMutex *babl_space_mutex;
+BablMutex *babl_remodel_mutex;
void
babl_internal_init (void)
@@ -93,6 +95,8 @@ babl_internal_init (void)
babl_fish_mutex = babl_mutex_new ();
babl_format_mutex = babl_mutex_new ();
babl_reference_mutex = babl_mutex_new ();
+ babl_space_mutex = babl_mutex_new ();
+ babl_remodel_mutex = babl_mutex_new ();
#if BABL_DEBUG_MEM
babl_debug_mutex = babl_mutex_new ();
#endif
diff --git a/babl/babl-internal.h b/babl/babl-internal.h
index b3c9785..38c4db5 100644
--- a/babl/babl-internal.h
+++ b/babl/babl-internal.h
@@ -249,6 +249,8 @@ extern int babl_in_fish_path;
extern BablMutex *babl_format_mutex;
extern BablMutex *babl_fish_mutex;
extern BablMutex *babl_reference_mutex;
+extern BablMutex *babl_space_mutex;
+extern BablMutex *babl_remodel_mutex;
#define BABL_DEBUG_MEM 0
#if BABL_DEBUG_MEM
@@ -362,13 +364,16 @@ void babl_store_db (void);
int _babl_max_path_len (void);
-const Babl *
-babl_trc_new (const char *name,
+extern const Babl *
+(*babl_trc_new) (const char *name,
BablTRCType type,
double gamma,
int n_lut,
float *lut);
+extern const Babl *
+(*babl_trc_lookup_by_name) (const char *name);
+
void babl_space_to_xyz (const Babl *space, const double *rgb, double *xyz);
void babl_space_from_xyz (const Babl *space, const double *xyz, double *rgb);
@@ -383,9 +388,11 @@ const char *
babl_conversion_create_name (Babl *source, Babl *destination, int type,
int allow_collision);
-void _babl_space_add_universal_rgb (const Babl *space);
+extern void (*_babl_space_add_universal_rgb) (const Babl *space);
+const Babl *
+babl_trc_formula_srgb (double gamma, double a, double b, double c, double d, double e, double f);
const Babl *
-babl_trc_formula_srgb (double gamma, double a, double b, double c, double d);
+babl_trc_formula_cie (double gamma, double a, double b, double c);
const Babl *babl_space_match_trc_matrix (const Babl *trc_red,
@@ -424,8 +431,6 @@ void babl_space_to_xyz (const Babl *space, const double *rgb, double *xyz);
*/
void babl_space_from_xyz (const Babl *space, const double *xyz, double *rgb);
-extern int _babl_instrument;
-
static inline void
babl_conversion_process (const Babl *babl,
const char *source,
@@ -433,8 +438,6 @@ babl_conversion_process (const Babl *babl,
long n)
{
BablConversion *conversion = (BablConversion *) babl;
- if (_babl_instrument)
- conversion->pixels += n;
conversion->dispatch (babl, source, destination, n, conversion->data);
}
@@ -465,4 +468,7 @@ char *babl_space_to_icc (const Babl *space,
Babl *
_babl_space_for_lcms (const char *icc_data, int icc_length); // XXX pass profile for dedup?
+void
+babl_trc_class_init (void);
+
#endif
diff --git a/babl/babl-introspect.c b/babl/babl-introspect.c
index 6230f92..00168cc 100644
--- a/babl/babl-introspect.c
+++ b/babl/babl-introspect.c
@@ -68,7 +68,7 @@ babl_introspect (Babl *babl)
babl_conversion_class_for_each (each_introspect, NULL);
babl_log ("");
babl_log ("trcs:");
- babl_trc_class_for_each (each_introspect, NULL);
+ //babl_trc_class_for_each (each_introspect, NULL);
babl_log ("");
babl_log ("spaces:");
babl_space_class_for_each (each_introspect, NULL);
diff --git a/babl/babl-matrix.h b/babl/babl-matrix.h
index 2107b31..714debc 100644
--- a/babl/babl-matrix.h
+++ b/babl/babl-matrix.h
@@ -9,7 +9,7 @@ static inline void babl_matrix_mul_matrix (const double *matA_,
const double *matB_,
double *out)
{
- int i, j;
+ unsigned int i, j;
double matA[9];
double matB[9];
double t1, t2, t3;
@@ -36,7 +36,7 @@ static inline void babl_matrix_mul_matrixf (const float *matA_,
const float *matB_,
float *out)
{
- int i, j;
+ unsigned int i, j;
float matA[9];
float matB[9];
float t1, t2, t3;
@@ -60,7 +60,7 @@ static inline void babl_matrix_mul_matrixf (const float *matA_,
static inline void babl_matrix_to_float (const double *in, float *out)
{
- int i;
+ unsigned int i;
for (i = 0; i < 9; i ++)
out[i] = in[i];
}
@@ -141,9 +141,9 @@ static inline void babl_matrix_mul_vectorff (const float *mat, const float *v_in
}
static inline void babl_matrix_mul_vectorff_buf3 (const float *mat, const float *v_in, float *v_out,
- int samples)
+ unsigned int samples)
{
- int i;
+ unsigned int i;
const float m_0_0 = m(mat, 0, 0);
const float m_0_1 = m(mat, 0, 1);
const float m_0_2 = m(mat, 0, 2);
@@ -166,7 +166,7 @@ static inline void babl_matrix_mul_vectorff_buf3 (const float *mat, const float
}
static inline void babl_matrix_mul_vectorff_buf4 (const float *mat, const float *v_in, float *v_out,
- int samples)
+ unsigned int samples)
{
const float m_0_0 = m(mat, 0, 0);
const float m_0_1 = m(mat, 0, 1);
@@ -177,7 +177,7 @@ static inline void babl_matrix_mul_vectorff_buf4 (const float *mat, const float
const float m_2_0 = m(mat, 2, 0);
const float m_2_1 = m(mat, 2, 1);
const float m_2_2 = m(mat, 2, 2);
- int i;
+ unsigned int i;
for (i = 0; i < samples; i ++)
{
float a = v_in[0], b = v_in[1], c = v_in[2];
@@ -192,9 +192,9 @@ static inline void babl_matrix_mul_vectorff_buf4 (const float *mat, const float
}
static inline void babl_matrix_mul_vector_buf4 (const double *mat, const double *v_in, double *v_out,
- int samples)
+ unsigned int samples)
{
- int i;
+ unsigned int i;
const double m_0_0 = m(mat, 0, 0);
const double m_0_1 = m(mat, 0, 1);
const double m_0_2 = m(mat, 0, 2);
diff --git a/babl/babl-memory.c b/babl/babl-memory.c
index 5c9214e..b7d83ef 100644
--- a/babl/babl-memory.c
+++ b/babl/babl-memory.c
@@ -318,8 +318,8 @@ babl_strcat (char *dest,
const char *src)
{
char *ret;
- int src_len;
- int dst_len;
+ size_t src_len;
+ size_t dst_len;
if (NULL == src)
return dest;
diff --git a/babl/babl-model.c b/babl/babl-model.c
index 44481ac..a2ec53a 100644
--- a/babl/babl-model.c
+++ b/babl/babl-model.c
@@ -382,8 +382,9 @@ babl_model_is_symmetric (const Babl *cbabl)
for (j = 0; j < 4; j++)
{
float tolerance = TOLERANCE;
+ /* this to adapt to value ranges outside 0-1 */
if (fabs(clipped[i*4+j]) > 1.0)
- tolerance = fabs(clipped[i*4+j]) * 0.01;
+ tolerance = fabs(clipped[i*4+j]) * TOLERANCE;
if (fabs (clipped[i *4 + j] - transformed[i * 4 + j]) > tolerance)
{
if (!log)
@@ -420,11 +421,9 @@ babl_model_is_symmetric (const Babl *cbabl)
BABL_CLASS_IMPLEMENT (model)
-/* XXX: probably better to do like with babl_format, add a -suffix and
- * insert in normal database than to have this static cache list
- */
-static const Babl *babl_remodels[512]={NULL,};
-int babl_n_remodels = 0;
+static Babl **babl_remodels = NULL;
+static int babl_remodel_size = 0;
+static int babl_n_remodels = 0;
const Babl *
babl_remodel_with_space (const Babl *model,
@@ -453,24 +452,37 @@ babl_remodel_with_space (const Babl *model,
assert (BABL_IS_BABL (model));
+ babl_mutex_lock (babl_remodel_mutex);
/* get back to the sRGB model if we are in a COW clone of it */
if (model->model.model)
model = (void*)model->model.model;
assert (BABL_IS_BABL (model));
+ if (babl_remodel_size < babl_n_remodels + 2)
+ {
+ int new_size = (babl_n_remodels + 2) * 2;
+ if (new_size < 256) new_size = 256;
+ babl_remodels = babl_realloc (babl_remodels, new_size * sizeof (Babl*));
+ babl_remodel_size = new_size;
+ }
for (i = 0; i < babl_n_remodels; i++)
{
if (babl_remodels[i]->model.model == model &&
babl_remodels[i]->model.space == space)
- return babl_remodels[i];
+ {
+ ret = (Babl*)babl_remodels[i];
+ babl_mutex_unlock (babl_remodel_mutex);
+ return ret;
+ }
}
ret = babl_calloc (sizeof (BablModel), 1);
memcpy (ret, model, sizeof (BablModel));
ret->model.space = space;
ret->model.model = (void*)model; /* use the data as a backpointer to original model */
- return babl_remodels[babl_n_remodels++] = ret;
+ babl_remodels[babl_n_remodels++] = ret;
+ babl_mutex_unlock (babl_remodel_mutex);
return (Babl*)ret;
}
diff --git a/babl/babl-palette.c b/babl/babl-palette.c
index 086da67..1db8fac 100644
--- a/babl/babl-palette.c
+++ b/babl/babl-palette.c
@@ -831,6 +831,10 @@ babl_new_palette_with_space (const char *name,
*palptr = default_palette ();;
cname[0] = 'v';
model_no_alpha = babl_model_new ("name", name, component, NULL);
+
+ babl_set_user_data (model, palptr);
+ babl_set_user_data (model_no_alpha, palptr);
+
cname[0] = '\\';
f_pal_a_u8 = (void*) babl_format_new ("name", name, model, space,
babl_type ("u8"),
@@ -924,9 +928,6 @@ babl_new_palette_with_space (const char *name,
"data", palptr,
NULL);
- babl_set_user_data (model, palptr);
- babl_set_user_data (model_no_alpha, palptr);
-
if (format_u8)
*format_u8 = f_pal_u8;
if (format_u8_with_alpha)
diff --git a/babl/babl-ref-pixels.inc b/babl/babl-ref-pixels.inc
index b706da7..9479d88 100644
--- a/babl/babl-ref-pixels.inc
+++ b/babl/babl-ref-pixels.inc
@@ -25,13 +25,13 @@ static const double babl_path_test_pixels[12288] = {
0.7718567535150, 0.7514902249684, 0.9248924855724, 0.0955070830395,
0.1025725035475, 0.4075078840402, 0.6785853950673, 0.9634626577438,
0.9553271694832, 0.1067870907051, 0.3603431430461, 0.5144157584358,
-0.2521084366609, 0.1242231042703, 0.2321393006631, 0.7137176574737,
+-0.2521084366609, 0.1242231042703, 0.2321393006631, 0.7137176574737,
0.7002526473721, 0.6853307782138, 0.3886525502376, 0.9672617432509,
0.4827699570371, 0.5637687419372, 0.9882396813427, 0.5632248975165,
-0.6371306197891, 0.7984740379259, 0.1965256124719, 0.5864613962297,
+0.6371306197891, 0.7984740379259, 1.1965256124719, 0.5864613962297,
0.8423190181341, 0.2221470797538, 0.1378166187265, 0.7468119350946,
0.0261717611114, 0.6141757711834, 0.9736373051878, 0.0627091038333,
-0.1666384582252, 0.1287442646589, 0.0216836552237, 0.6522226997894,
+0.1666384582252, 0.1287442646589, -0.0216836552237, 0.6522226997894,
0.0957444552778, 0.1219656272428, 0.2355313558297, 0.3820267982697,
0.4349323992780, 0.3478528919387, 0.2461887315131, 0.4676706564928,
0.1980661788015, 0.1351850461844, 0.0331836701525, 0.6348412817506,
@@ -39,7 +39,7 @@ static const double babl_path_test_pixels[12288] = {
0.6422913356881, 0.2450153670483, 0.4793101737645, 0.8954794010592,
0.6798358967900, 0.4846103533565, 0.4671624468021, 0.6171267924910,
0.0930224513137, 0.7060076579014, 0.0987861240743, 0.4407997515243,
-0.5024965775677, 0.2596609095389, 0.8347519230259, 0.1204697792979,
+0.5024965775677, 0.2596609095389, 2.8347519230259, 0.1204697792979,
0.5379539348827, 0.5982410328455, 0.3816265367817, 0.0702832783900,
0.2626565495798, 0.9728863341608, 0.9460939252498, 0.6278152682948,
0.0007009459663, 0.4607227283813, 0.1080713798795, 0.9792775954023,
@@ -3096,7 +3096,7 @@ static const double babl_path_test_pixels[12288] = {
0.5395579815561, 0.2107098112864, 0.5031076616156, 0.4885859840962,
};
-static const int babl_num_conversion_test_pixels = 128;
+static const int babl_num_conversion_test_pixels = 32;
static const double *babl_conversion_test_pixels = babl_path_test_pixels;
diff --git a/babl/babl-space.c b/babl/babl-space.c
index c662629..56570b5 100644
--- a/babl/babl-space.c
+++ b/babl/babl-space.c
@@ -25,9 +25,9 @@
static BablSpace space_db[MAX_SPACES];
-static void babl_chromatic_adaptation_matrix (const double *whitepoint,
- const double *target_whitepoint,
- double *chad_matrix)
+void babl_chromatic_adaptation_matrix (const double *whitepoint,
+ const double *target_whitepoint,
+ double *chad_matrix)
{
double bradford[9]={ 0.8951000, 0.2664000, -0.1614000,
-0.7502000, 1.7135000, 0.0367000,
@@ -93,6 +93,36 @@ XYZ_to_LAB (double X,
*to_b = 200.0 * (f_y - f_z);
}
+// cached equalized matrices generated for spaces used internally by babl
+//
+static double equalized_matrices[][9]=
+{
+ {0.673492431640625000, 0.165679931640625000, 0.125030517578125000,
+ 0.279052734375000000, 0.675354003906250000, 0.045593261718750000,
+ -0.001907348632812500, 0.029968261718750000, 0.796844482421875000},
+
+ {0.609756469726562500, 0.205276489257812500, 0.149169921875000000,
+ 0.311126708984375000, 0.625671386718750000, 0.063201904296875000,
+ 0.019485473632812500, 0.060867309570312500, 0.744552612304687500},
+
+ {0.797714233398437500, 0.135208129882812500, 0.031280517578125000,
+ 0.288070678710937500, 0.711868286132812500, 0.000061035156250000,
+ 0.000015258789062500, 0.000015258789062500, 0.824874877929687500},
+
+ {0.475555419921875000, 0.339706420898437500, 0.148941040039062500,
+ 0.255172729492187500, 0.672592163085937500, 0.072235107421875000,
+ 0.018463134765625000, 0.113342285156250000, 0.693099975585937500},
+
+ {0.689895629882812500, 0.149765014648437500, 0.124542236328125000,
+ 0.284530639648437500, 0.671691894531250000, 0.043777465820312500,
+ -0.006011962890625000, 0.009994506835937500, 0.820922851562500000},
+
+ {0.990905761718750000, 0.012222290039062500,-0.038925170898437500,
+ 0.361907958984375000, 0.722503662109375000,-0.084411621093750000,
+ -0.002685546875000000, 0.008239746093750000, 0.819351196289062500},
+};
+
+
/* round all values to s15f16 precision and brute-force
* jitter +/- 1 all entries for best uniform gray axis - this
* also optimizes the accuracy of the matrix for floating point
@@ -117,6 +147,26 @@ babl_matrix_equalize (double *in_mat)
double best_error = 1000000.0;
int i;
+ for (int i = 0; i < sizeof (equalized_matrices)/
+ sizeof (equalized_matrices[0]); i++)
+ {
+ double diff_sum = 0.0f;
+ for (int j = 0; j < 9; j++){
+ double diff = equalized_matrices[i][j] - in_mat[j];
+ diff *= diff;
+ diff_sum += diff; }
+
+ // the threshold is based on being ~double the biggest
+ // difference seen in the default space set.
+
+ if (diff_sum < 0.000000005) {
+ for (int j = 0; j < 9; j++){
+ in_mat[j] = equalized_matrices[i][j];
+ }
+ return;
+ }
+ }
+
for (i = 0; i < 9; i++)
best_j[i] = 0;
@@ -162,11 +212,23 @@ babl_matrix_equalize (double *in_mat)
memcpy (&best_j[0], &j[0], sizeof (best_j));
}
}
+
for (i = 0; i < 9; i++)
{
int32_t val = in_mat[i] * 65536.0 + 0.5f;
in_mat[i] = val / 65536.0 + best_j[i] / 65536.0;
}
+
+#if 0 // uncomment to generate code for pasting in cache
+ fprintf (stderr, "{");
+ for (i = 0; i < 9; i++)
+ {
+ if (i)
+ fprintf (stderr, ", ");
+ fprintf (stderr, "%.18f", in_mat[i]);
+ }
+ fprintf (stderr, "},\n");
+#endif
}
static void
@@ -244,7 +306,6 @@ _babl_space_for_lcms (const char *icc_data,
memset (&space, 0, sizeof(space));
space.instance.class_type = BABL_SPACE;
space.instance.id = 0;
- space.icc_type = BablICCTypeCMYK;
if (i >= MAX_SPACES-1)
{
@@ -355,11 +416,13 @@ babl_space_from_rgbxyz_matrix (const char *name,
if (name)
snprintf (space_db[i].name, sizeof (space_db[i].name), "%s", name);
else
- /* XXX: this can get longer than 256bytes ! */
- snprintf (space_db[i].name, sizeof (space_db[i].name),
+ {
+ snprintf (space_db[i].name, sizeof (space_db[i].name)-1,
"space-%.4f,%.4f_%.4f,%.4f_%.4f,%.4f_%.4f,%.4f_%s,%s,%s",
wx,wy,rx,ry,bx,by,gx,gy,babl_get_name (space.trc[0]),
babl_get_name(space.trc[1]), babl_get_name(space.trc[2]));
+ space_db[i].name[sizeof (space_db[i].name)-1]=0;
+ }
babl_space_get_icc ((Babl*)&space_db[i], NULL);
return (Babl*)&space_db[i];
@@ -676,650 +739,6 @@ babl_space_get_rgbtoxyz (const Babl *space)
return space->space.RGBtoXYZ;
}
-///////////////////
-
-
-static void
-prep_conversion (const Babl *babl)
-{
- Babl *conversion = (void*) babl;
- const Babl *source_space = babl_conversion_get_source_space (conversion);
- float *matrixf;
- int i;
- float *lut_red;
- float *lut_green;
- float *lut_blue;
-
- double matrix[9];
- babl_matrix_mul_matrix (
- (conversion->conversion.destination)->format.space->space.XYZtoRGB,
- (conversion->conversion.source)->format.space->space.RGBtoXYZ,
- matrix);
-
- matrixf = babl_calloc (sizeof (float), 9 + 256 * 3); // we leak this matrix , which is a singleton
- babl_matrix_to_float (matrix, matrixf);
- conversion->conversion.data = matrixf;
-
- lut_red = matrixf + 9;
- lut_green = lut_red + 256;
- lut_blue = lut_green + 256;
- for (i = 0; i < 256; i++)
- {
- lut_red[i] = babl_trc_to_linear (source_space->space.trc[0], i/255.0);
- lut_green[i] = babl_trc_to_linear (source_space->space.trc[1], i/255.0);
- lut_blue[i] = babl_trc_to_linear (source_space->space.trc[2], i/255.0);
- }
-}
-
-#define TRC_IN(rgba_in, rgba_out) do{ int i;\
- for (i = 0; i < samples; i++) \
- { \
- rgba_out[i*4+3] = rgba_in[i*4+3]; \
- } \
- if ((source_space->space.trc[0] == source_space->space.trc[1]) && \
- (source_space->space.trc[1] == source_space->space.trc[2])) \
- { \
- const Babl *trc = (void*)source_space->space.trc[0]; \
- babl_trc_to_linear_buf(trc, rgba_in, rgba_out, 4, 4, 3, samples); \
- } \
- else \
- { \
- int c; \
- for (c = 0; c < 3; c ++) \
- { \
- const Babl *trc = (void*)source_space->space.trc[c]; \
- babl_trc_to_linear_buf(trc, rgba_in + c, rgba_out + c, 4, 4, 1, samples); \
- } \
- } \
-}while(0)
-
-#define TRC_OUT(rgba_in, rgba_out) do{\
- { \
- int c; \
- if ((destination_space->space.trc[0] == destination_space->space.trc[1]) && \
- (destination_space->space.trc[1] == destination_space->space.trc[2])) \
- { \
- const Babl *trc = (void*)destination_space->space.trc[0]; \
- babl_trc_from_linear_buf(trc, rgba_in, rgba_out, 4, 4, 3, samples); \
- } \
- else \
- { \
- for (c = 0; c < 3; c ++) \
- { \
- const Babl *trc = (void*)destination_space->space.trc[c]; \
- babl_trc_from_linear_buf(trc, rgba_in + c, rgba_out + c, 4, 4, 1, samples); \
- } \
- } \
- }\
-} while(0)
-
-
-
-
-static inline void
-universal_nonlinear_rgba_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *source_space = babl_conversion_get_source_space (conversion);
- const Babl *destination_space = babl_conversion_get_destination_space (conversion);
-
- float * matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- TRC_IN(rgba_in, rgba_out);
-
- babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
-
- TRC_OUT(rgba_out, rgba_out);
-}
-
-static inline void
-universal_nonlinear_rgb_linear_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *source_space = babl_conversion_get_source_space (conversion);
- float * matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- TRC_IN(rgba_in, rgba_out);
-
- babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
-}
-
-static inline void
-universal_linear_rgb_nonlinear_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *destination_space = conversion->conversion.destination->format.space;
- float * matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples);
-
- TRC_OUT(rgba_out, rgba_out);
-}
-
-static inline void
-universal_nonlinear_rgba_u8_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *destination_space = conversion->conversion.destination->format.space;
-
- float * matrixf = data;
- float * in_trc_lut_red = matrixf + 9;
- float * in_trc_lut_green = in_trc_lut_red + 256;
- float * in_trc_lut_blue = in_trc_lut_green + 256;
- int i;
- uint8_t *rgba_in_u8 = (void*)src_char;
- uint8_t *rgba_out_u8 = (void*)dst_char;
-
- float *rgb = babl_malloc (sizeof(float) * 4 * samples);
-
- for (i = 0; i < samples; i++)
- {
- rgb[i*4+0]=in_trc_lut_red[rgba_in_u8[i*4+0]];
- rgb[i*4+1]=in_trc_lut_green[rgba_in_u8[i*4+1]];
- rgb[i*4+2]=in_trc_lut_blue[rgba_in_u8[i*4+2]];
- rgba_out_u8[i*4+3] = rgba_in_u8[i*4+3];
- }
-
- babl_matrix_mul_vectorff_buf4 (matrixf, rgb, rgb, samples);
-
- {
- const Babl *from_trc_red = (void*)destination_space->space.trc[0];
- const Babl *from_trc_green = (void*)destination_space->space.trc[1];
- const Babl *from_trc_blue = (void*)destination_space->space.trc[2];
- for (i = 0; i < samples * 4; i+=4)
- {
- rgba_out_u8[i+0] = babl_trc_from_linear (from_trc_red, rgb[i+0]) * 255.5f;
- rgba_out_u8[i+1] = babl_trc_from_linear (from_trc_green, rgb[i+1]) * 255.5f;
- rgba_out_u8[i+2] = babl_trc_from_linear (from_trc_blue, rgb[i+2]) * 255.5f;
- }
- }
- babl_free (rgb);
-}
-
-
-static inline void
-universal_rgba_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- float *matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples);
-}
-
-static inline void
-universal_rgb_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- float *matrixf = data;
- float *rgb_in = (void*)src_char;
- float *rgb_out = (void*)dst_char;
-
- babl_matrix_mul_vectorff_buf3 (matrixf, rgb_in, rgb_out, samples);
-}
-
-
-static inline void
-universal_ya_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- memcpy (dst_char, src_char, samples * 4 * 2);
-}
-
-static inline void
-universal_y_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- memcpy (dst_char, src_char, samples * 4);
-}
-
-
-static inline void
-universal_nonlinear_rgb_u8_converter (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *destination_space = conversion->conversion.destination->format.space;
-
- float * matrixf = data;
- float * in_trc_lut_red = matrixf + 9;
- float * in_trc_lut_green = in_trc_lut_red + 256;
- float * in_trc_lut_blue = in_trc_lut_green + 256;
- int i;
- uint8_t *rgb_in_u8 = (void*)src_char;
- uint8_t *rgb_out_u8 = (void*)dst_char;
-
- float *rgba_out = babl_malloc (sizeof(float) * 4 * samples);
-
- for (i = 0; i < samples; i++)
- {
- rgba_out[i*4+0]=in_trc_lut_red[rgb_in_u8[i*3+0]];
- rgba_out[i*4+1]=in_trc_lut_green[rgb_in_u8[i*3+1]];
- rgba_out[i*4+2]=in_trc_lut_blue[rgb_in_u8[i*3+2]];
- rgba_out[i*4+3]=rgb_in_u8[i*3+2] * 255.5f;
- }
-
- babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
-
- {
- int c;
- TRC_OUT(rgba_out, rgba_out);
-
- for (i = 0; i < samples; i++)
- for (c = 0; c < 3; c ++)
- rgb_out_u8[i*3+c] = rgba_out[i*4+c] * 255.5f;
- }
-
- babl_free (rgba_out);
-}
-
-
-#if defined(USE_SSE2)
-
-#define m(matr, j, i) matr[j*3+i]
-
-#include <emmintrin.h>
-
-static inline void babl_matrix_mul_vectorff_buf4_sse2 (const float *mat,
- const float *v_in,
- float *v_out,
- int samples)
-{
- const __v4sf m___0 = {m(mat, 0, 0), m(mat, 1, 0), m(mat, 2, 0), 0};
- const __v4sf m___1 = {m(mat, 0, 1), m(mat, 1, 1), m(mat, 2, 1), 0};
- const __v4sf m___2 = {m(mat, 0, 2), m(mat, 1, 2), m(mat, 2, 2), 1};
- int i;
- for (i = 0; i < samples; i ++)
- {
- __v4sf a, b, c = _mm_load_ps(&v_in[0]);
- a = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(0,0,0,0));
- b = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(1,1,1,1));
- c = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(3,2,2,2));
- _mm_store_ps (v_out, m___0 * a + m___1 * b + m___2 * c);
- v_out += 4;
- v_in += 4;
- }
- _mm_empty ();
-}
-
-#undef m
-
-
-static inline void
-universal_nonlinear_rgba_converter_sse2 (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *source_space = babl_conversion_get_source_space (conversion);
- const Babl *destination_space = babl_conversion_get_destination_space (conversion);
- float * matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- TRC_IN(rgba_in, rgba_out);
-
- babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
-
- TRC_OUT(rgba_out, rgba_out);
-}
-
-
-static inline void
-universal_rgba_converter_sse2 (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- float *matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples);
-}
-
-static inline void
-universal_nonlinear_rgba_u8_converter_sse2 (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *destination_space = conversion->conversion.destination->format.space;
-
- float * matrixf = data;
- float * in_trc_lut_red = matrixf + 9;
- float * in_trc_lut_green = in_trc_lut_red + 256;
- float * in_trc_lut_blue = in_trc_lut_green + 256;
- int i;
- uint8_t *rgba_in_u8 = (void*)src_char;
- uint8_t *rgba_out_u8 = (void*)dst_char;
-
- float *rgba_out = babl_malloc (sizeof(float) * 4 * samples);
-
- for (i = 0; i < samples * 4; i+= 4)
- {
- rgba_out[i+0]=in_trc_lut_red[rgba_in_u8[i+0]];
- rgba_out[i+1]=in_trc_lut_green[rgba_in_u8[i+1]];
- rgba_out[i+2]=in_trc_lut_blue[rgba_in_u8[i+2]];
- rgba_out_u8[i+3] = rgba_in_u8[i+3];
- }
-
- babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
-
- {
- int c;
- TRC_OUT(rgba_out, rgba_out);
-
- for (i = 0; i < samples * 4; i+= 4)
- for (c = 0; c < 3; c ++)
- rgba_out_u8[i+c] = rgba_out[i+c] * 255.5f;
- }
-
- babl_free (rgba_out);
-}
-
-static inline void
-universal_nonlinear_rgb_u8_converter_sse2 (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *destination_space = conversion->conversion.destination->format.space;
-
- float * matrixf = data;
- float * in_trc_lut_red = matrixf + 9;
- float * in_trc_lut_green = in_trc_lut_red + 256;
- float * in_trc_lut_blue = in_trc_lut_green + 256;
- int i;
- uint8_t *rgb_in_u8 = (void*)src_char;
- uint8_t *rgb_out_u8 = (void*)dst_char;
-
- float *rgba_out = babl_malloc (sizeof(float) * 4 * samples);
-
- for (i = 0; i < samples; i++)
- {
- rgba_out[i*4+0]=in_trc_lut_red[rgb_in_u8[i*3+0]];
- rgba_out[i*4+1]=in_trc_lut_green[rgb_in_u8[i*3+1]];
- rgba_out[i*4+2]=in_trc_lut_blue[rgb_in_u8[i*3+2]];
- }
-
- babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
-
- {
- int c;
- TRC_OUT(rgba_out, rgba_out);
-
- for (i = 0; i < samples; i++)
- for (c = 0; c < 3; c ++)
- rgb_out_u8[i*3+c] = rgba_out[i*4+c] * 255.5f;
- }
-
- babl_free (rgba_out);
-}
-
-
-static inline void
-universal_nonlinear_rgb_linear_converter_sse2 (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *source_space = babl_conversion_get_source_space (conversion);
- float * matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- TRC_IN(rgba_in, rgba_out);
-
- babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
-}
-
-
-static inline void
-universal_linear_rgb_nonlinear_converter_sse2 (const Babl *conversion,
- unsigned char *src_char,
- unsigned char *dst_char,
- long samples,
- void *data)
-{
- const Babl *destination_space = conversion->conversion.destination->format.space;
- float * matrixf = data;
- float *rgba_in = (void*)src_char;
- float *rgba_out = (void*)dst_char;
-
- babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples);
-
- TRC_OUT(rgba_out, rgba_out);
-}
-#endif
-
-
-static int
-add_rgb_adapter (Babl *babl,
- void *space)
-{
- if (babl != space)
- {
-
-#if defined(USE_SSE2)
- if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE) &&
- (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2))
- {
-
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", space),
- babl_format_with_space("RGBA float", babl),
- "linear", universal_rgba_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", babl),
- babl_format_with_space("RGBA float", space),
- "linear", universal_rgba_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", space),
- babl_format_with_space("R'G'B'A float", babl),
- "linear", universal_nonlinear_rgba_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", babl),
- babl_format_with_space("R'G'B'A float", space),
- "linear", universal_nonlinear_rgba_converter_sse2,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", space),
- babl_format_with_space("RGBA float", babl),
- "linear", universal_nonlinear_rgb_linear_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", babl),
- babl_format_with_space("RGBA float", space),
- "linear", universal_nonlinear_rgb_linear_converter_sse2,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", babl),
- babl_format_with_space("R'G'B'A float", space),
- "linear", universal_linear_rgb_nonlinear_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", space),
- babl_format_with_space("R'G'B'A float", babl),
- "linear", universal_linear_rgb_nonlinear_converter_sse2,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A u8", space),
- babl_format_with_space("R'G'B'A u8", babl),
- "linear", universal_nonlinear_rgba_u8_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A u8", babl),
- babl_format_with_space("R'G'B'A u8", space),
- "linear", universal_nonlinear_rgba_u8_converter_sse2,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B' u8", space),
- babl_format_with_space("R'G'B' u8", babl),
- "linear", universal_nonlinear_rgb_u8_converter_sse2,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B' u8", babl),
- babl_format_with_space("R'G'B' u8", space),
- "linear", universal_nonlinear_rgb_u8_converter_sse2,
- NULL));
- }
- //else
-#endif
- {
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", space),
- babl_format_with_space("RGBA float", babl),
- "linear", universal_rgba_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", babl),
- babl_format_with_space("RGBA float", space),
- "linear", universal_rgba_converter,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", space),
- babl_format_with_space("R'G'B'A float", babl),
- "linear", universal_nonlinear_rgba_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", babl),
- babl_format_with_space("R'G'B'A float", space),
- "linear", universal_nonlinear_rgba_converter,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", space),
- babl_format_with_space("RGBA float", babl),
- "linear", universal_nonlinear_rgb_linear_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A float", babl),
- babl_format_with_space("RGBA float", space),
- "linear", universal_nonlinear_rgb_linear_converter,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A u8", space),
- babl_format_with_space("R'G'B'A u8", babl),
- "linear", universal_nonlinear_rgba_u8_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B'A u8", babl),
- babl_format_with_space("R'G'B'A u8", space),
- "linear", universal_nonlinear_rgba_u8_converter,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B' u8", space),
- babl_format_with_space("R'G'B' u8", babl),
- "linear", universal_nonlinear_rgb_u8_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("R'G'B' u8", babl),
- babl_format_with_space("R'G'B' u8", space),
- "linear", universal_nonlinear_rgb_u8_converter,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", babl),
- babl_format_with_space("R'G'B'A float", space),
- "linear", universal_linear_rgb_nonlinear_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGBA float", space),
- babl_format_with_space("R'G'B'A float", babl),
- "linear", universal_linear_rgb_nonlinear_converter,
- NULL));
- }
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGB float", space),
- babl_format_with_space("RGB float", babl),
- "linear", universal_rgb_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("RGB float", babl),
- babl_format_with_space("RGB float", space),
- "linear", universal_rgb_converter,
- NULL));
-
- prep_conversion(babl_conversion_new(
- babl_format_with_space("Y float", space),
- babl_format_with_space("Y float", babl),
- "linear", universal_y_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("YaA float", babl),
- babl_format_with_space("YaA float", space),
- "linear", universal_ya_converter,
- NULL));
- prep_conversion(babl_conversion_new(
- babl_format_with_space("YA float", babl),
- babl_format_with_space("YA float", space),
- "linear", universal_ya_converter,
- NULL));
- }
- return 0;
-}
-
-/* The first time a new Babl space is used - for creation of a fish, is when
- * this function is called, it adds conversions hooks that provides its formats
- * with conversions internally as well as for conversions to and from other RGB
- * spaces.
- */
-void
-_babl_space_add_universal_rgb (const Babl *space)
-{
- babl_space_class_for_each (add_rgb_adapter, (void*)space);
-}
const Babl *
diff --git a/babl/babl-space.h b/babl/babl-space.h
index 86692e9..b9b5dd4 100644
--- a/babl/babl-space.h
+++ b/babl/babl-space.h
@@ -171,5 +171,10 @@ babl_space_from_gray_trc (const char *name,
const Babl *trc_gray,
BablSpaceFlags flags);
+void
+babl_chromatic_adaptation_matrix (const double *whitepoint,
+ const double *target_whitepoint,
+ double *chad_matrix);
+
#endif
diff --git a/babl/babl-util.c b/babl/babl-util.c
index cab9ab1..2b78a5e 100644
--- a/babl/babl-util.c
+++ b/babl/babl-util.c
@@ -17,14 +17,22 @@
*/
#include "config.h"
+#include <stdarg.h>
+#include <limits.h>
+#include <assert.h>
+#include <stdio.h>
#include <math.h>
+#include <sys/types.h>
+#include <sys/stat.h>
#include "babl-internal.h"
#ifdef __WIN32__
#include <windows.h>
+#include <wchar.h>
#else
#include <sys/time.h>
#include <time.h>
+#include <dirent.h>
#endif
#ifdef __WIN32__
@@ -101,6 +109,223 @@ babl_rel_avg_error (const double *imgA,
return error;
}
+size_t
+add_check_overflow (size_t numbers_count, ...)
+{
+ size_t result = 0;
+ va_list args;
+
+ assert (numbers_count > 0);
+
+ va_start (args, numbers_count);
+ while (numbers_count--)
+ {
+ size_t addendum = va_arg (args, size_t);
+
+ if ((SIZE_MAX - result) < addendum)
+ {
+ result = 0;
+ break;
+ }
+
+ result += addendum;
+ }
+ va_end (args);
+
+ return result;
+}
+
+size_t
+mul_check_overflow (size_t numbers_count, ...)
+{
+ size_t result = 1;
+ va_list args;
+
+ assert (numbers_count > 0);
+
+ va_start (args, numbers_count);
+ while (numbers_count--)
+ {
+ size_t factor = va_arg (args, size_t);
+
+ if ((SIZE_MAX / result) < factor)
+ {
+ result = 0;
+ break;
+ }
+
+ result *= factor;
+ }
+ va_end (args);
+
+ return result;
+}
+
+FILE *
+_babl_fopen (const char *path,
+ const char *mode)
+{
+#ifndef _WIN32
+ return fopen (path, mode);
+#else
+ wchar_t *path_utf16 = babl_convert_utf8_to_utf16 (path);
+ wchar_t *mode_utf16 = babl_convert_utf8_to_utf16 (mode);
+ FILE *result = NULL;
+
+ result = _wfopen (path_utf16, mode_utf16);
+
+ if (path_utf16)
+ babl_free (path_utf16);
+
+ if (mode_utf16)
+ babl_free (mode_utf16);
+
+ return result;
+#endif
+}
+
+int
+_babl_remove (const char *path)
+{
+#ifndef _WIN32
+ return remove (path);
+#else
+ wchar_t *path_utf16 = babl_convert_utf8_to_utf16 (path);
+ int result = 0;
+
+ result = _wremove (path_utf16);
+
+ if (path_utf16)
+ babl_free (path_utf16);
+
+ return result;
+#endif
+}
+
+int
+_babl_rename (const char *oldname,
+ const char *newname)
+{
+#ifndef _WIN32
+ return rename (oldname, newname);
+#else
+ wchar_t *oldname_utf16 = babl_convert_utf8_to_utf16 (oldname);
+ wchar_t *newname_utf16 = babl_convert_utf8_to_utf16 (newname);
+ int result = 0;
+
+ result = _wrename (oldname_utf16, newname_utf16);
+
+ if (oldname_utf16)
+ babl_free (oldname_utf16);
+
+ if (newname_utf16)
+ babl_free (newname_utf16);
+
+ return result;
+#endif
+}
+
+int
+_babl_stat (const char *path,
+ BablStat *buffer)
+{
+#ifndef _WIN32
+ return stat (path, buffer);
+#else
+ wchar_t *path_utf16 = babl_convert_utf8_to_utf16 (path);
+ int result = 0;
+
+ result = _wstat64 (path_utf16, buffer);
+
+ if (path_utf16)
+ babl_free (path_utf16);
+
+ return result;
+#endif
+}
+
+int
+_babl_mkdir (const char *path,
+ int mode)
+{
+#ifndef _WIN32
+ return mkdir (path, (mode_t) mode);
+#else
+ wchar_t *path_utf16 = babl_convert_utf8_to_utf16 (path);
+ int result = 0;
+ (void) mode;
+
+ result = _wmkdir (path_utf16);
+
+ if (path_utf16)
+ babl_free (path_utf16);
+
+ return result;
+#endif
+}
+
+void
+_babl_dir_foreach (const char *path,
+ _babl_dir_foreach_cb_t callback,
+ void *user_data)
+{
+#ifndef _WIN32
+ DIR *dir = opendir (path);
+
+ if (!path)
+ return;
+
+ if (dir != NULL)
+ {
+ struct dirent *dentry;
+
+ while ((dentry = readdir (dir)))
+ callback (path, dentry->d_name, user_data);
+
+ closedir (dir);
+ }
+#else
+ char *search = NULL;
+ wchar_t *search_utf16 = NULL;
+ struct _wfinddata64_t info;
+ intptr_t search_id = 0;
+
+ if (!path)
+ return;
+
+ search = babl_strcat (search, path);
+ search = babl_strcat (search, "\\*");
+ search_utf16 = babl_convert_utf8_to_utf16 (search);
+ if (!search_utf16)
+ goto cleanup;
+
+ memset (&info, 0, sizeof (info));
+ if ((search_id = _wfindfirst64 (search_utf16, &info)) != (intptr_t)-1)
+ {
+ do
+ {
+ char *entry = babl_convert_utf16_to_utf8 (info.name);
+
+ if (entry)
+ {
+ callback (path, entry, user_data);
+ babl_free (entry);
+ }
+ }
+ while (_wfindnext64 (search_id, &info) == 0);
+
+ _findclose (search_id);
+ }
+
+cleanup:
+ if (search_utf16)
+ babl_free (search_utf16);
+
+ if (search)
+ babl_free (search);
+#endif
+}
+
int
_babl_file_get_contents (const char *path,
char **contents,
@@ -111,7 +336,7 @@ _babl_file_get_contents (const char *path,
long size;
char *buffer;
- file = fopen (path,"rb");
+ file = _babl_fopen (path, "rb");
if (!file)
return -1;
@@ -148,3 +373,82 @@ _babl_file_get_contents (const char *path,
return 0;
}
+#ifdef _WIN32
+
+wchar_t *
+babl_convert_utf8_to_utf16 (const char *str)
+{
+ int wchar_count = 0;
+ wchar_t *wstr = NULL;
+
+ if (!str)
+ return NULL;
+
+ wchar_count = MultiByteToWideChar (CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ str, -1,
+ NULL, 0);
+ if (wchar_count <= 0)
+ return NULL;
+
+ wstr = babl_malloc (wchar_count * sizeof (wchar_t));
+ if (!wstr)
+ return NULL;
+
+ wchar_count = MultiByteToWideChar (CP_UTF8,
+ MB_ERR_INVALID_CHARS,
+ str, -1,
+ wstr, wchar_count);
+ if (wchar_count <= 0)
+ {
+ babl_free (wstr);
+ return NULL;
+ }
+
+ return wstr;
+}
+
+char *
+babl_convert_utf16_to_utf8 (const wchar_t *wstr)
+{
+ int char_count = 0;
+ char *str = NULL;
+
+ if (!wstr)
+ return NULL;
+
+ char_count = WideCharToMultiByte (CP_UTF8,
+ WC_ERR_INVALID_CHARS,
+ wstr, -1,
+ NULL, 0,
+ NULL, NULL);
+ if (char_count <= 0)
+ return NULL;
+
+ str = babl_malloc (char_count);
+ if (!str)
+ return NULL;
+
+ char_count = WideCharToMultiByte (CP_UTF8,
+ WC_ERR_INVALID_CHARS,
+ wstr, -1,
+ str, char_count,
+ NULL, NULL);
+ if (char_count <= 0)
+ {
+ babl_free (str);
+ return NULL;
+ }
+
+ return str;
+}
+
+extern IMAGE_DOS_HEADER __ImageBase;
+
+void *
+get_libbabl_module (void)
+{
+ return &__ImageBase;
+}
+
+#endif /* _WIN32 */
diff --git a/babl/babl-util.h b/babl/babl-util.h
index 9caec36..fce8e8f 100644
--- a/babl/babl-util.h
+++ b/babl/babl-util.h
@@ -19,6 +19,17 @@
#ifndef _BABL_UTIL_H
#define _BABL_UTIL_H
+#include <stddef.h>
+#include <stdio.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+
+#ifndef _WIN32
+typedef struct stat BablStat;
+#else
+typedef struct _stat64 BablStat;
+#endif
+
long
babl_ticks (void);
@@ -26,4 +37,53 @@ double
babl_rel_avg_error (const double *imgA,
const double *imgB,
long samples);
+
+size_t
+add_check_overflow (size_t numbers_count, ...);
+
+size_t
+mul_check_overflow (size_t numbers_count, ...);
+
+FILE *
+_babl_fopen (const char *path,
+ const char *mode);
+
+int
+_babl_remove (const char *path);
+
+int
+_babl_rename (const char *oldname,
+ const char *newname);
+
+int
+_babl_stat (const char *path,
+ BablStat *buffer);
+
+int
+_babl_mkdir (const char *path,
+ int mode);
+
+typedef void
+(*_babl_dir_foreach_cb_t) (const char *base_path,
+ const char *entry,
+ void *data);
+
+void
+_babl_dir_foreach (const char *path,
+ _babl_dir_foreach_cb_t callback,
+ void *user_data);
+
+#ifdef _WIN32
+
+wchar_t *
+babl_convert_utf8_to_utf16 (const char *str);
+
+char *
+babl_convert_utf16_to_utf8 (const wchar_t *wstr);
+
+void *
+get_libbabl_module (void);
+
+#endif /* _WIN32 */
+
#endif
diff --git a/babl/babl.c b/babl/babl.c
index fd90323..23db1a3 100644
--- a/babl/babl.c
+++ b/babl/babl.c
@@ -18,38 +18,13 @@
#include "config.h"
#include "babl-internal.h"
+#include "babl-base.h"
static int ref_count = 0;
-#ifdef _WIN32
-static HMODULE libbabl_dll = NULL;
-
-/* Minimal DllMain that just stores the handle to this DLL */
-
-/* Avoid silly "no previous prototype" gcc warning */
-BOOL WINAPI
-DllMain (HINSTANCE hinstDLL,
- DWORD fdwReason,
- LPVOID lpvReserved);
-
-BOOL WINAPI
-DllMain (HINSTANCE hinstDLL,
- DWORD fdwReason,
- LPVOID lpvReserved)
-{
- switch (fdwReason)
- {
- case DLL_PROCESS_ATTACH:
- libbabl_dll = hinstDLL;
- break;
- }
-
- return TRUE;
-}
-
-#else
+#ifndef _WIN32
#define BABL_PATH LIBDIR BABL_DIR_SEPARATOR BABL_LIBRARY
-#endif /* _WIN32 */
+#endif
/*
* Returns a list of directories if the environment variable $BABL_PATH
@@ -69,21 +44,16 @@ babl_dir_list (void)
{
#ifdef _WIN32
/* Figure it out from the location of this DLL */
- char *filename;
- int filename_size;
- char *sep1, *sep2;
-
wchar_t w_filename[MAX_PATH];
+ char *filename = NULL;
+ char *sep1, *sep2;
DWORD nSize = sizeof (w_filename) / sizeof ((w_filename)[0]);
- if (GetModuleFileNameW (libbabl_dll, w_filename, nSize) == 0)
+ if (GetModuleFileNameW (get_libbabl_module (), w_filename, nSize) == 0)
babl_fatal ("GetModuleFilenameW failed");
- filename_size = WideCharToMultiByte (CP_UTF8, 0, w_filename, -1, NULL, 0,
- NULL, NULL);
- filename = babl_malloc (sizeof (char) * filename_size);
- if (!WideCharToMultiByte (CP_UTF8, 0, w_filename, -1,
- filename, filename_size, NULL, NULL))
+ filename = babl_convert_utf16_to_utf8 (w_filename);
+ if (!filename)
babl_fatal ("Converting module filename to UTF-8 failed");
/* If the DLL file name is of the format
@@ -125,10 +95,14 @@ babl_dir_list (void)
return ret;
}
+
+static const char **simd_init (void);
void
babl_init (void)
{
+ const char **exclusion_pattern;
babl_cpu_accel_set_use (1);
+ exclusion_pattern = simd_init ();
if (ref_count++ == 0)
{
@@ -139,6 +113,7 @@ babl_init (void)
babl_type_db ();
babl_trc_class_init ();
babl_space_class_init ();
+ _babl_legal_error ();
babl_component_db ();
babl_model_db ();
babl_format_db ();
@@ -151,10 +126,11 @@ babl_init (void)
babl_sanity ();
dir_list = babl_dir_list ();
- babl_extension_load_dir_list (dir_list);
+ babl_extension_load_dir_list (dir_list, exclusion_pattern);
babl_free (dir_list);
- babl_init_db ();
+ if (!getenv ("BABL_INHIBIT_CACHE"))
+ babl_init_db ();
}
}
@@ -190,3 +166,123 @@ babl_model_is (const Babl *babl,
return babl && ((babl)==babl_model_with_space(model, babl));
}
+
+#include "babl-cpuaccel.h"
+void (*babl_base_init) (void) = babl_base_init_generic;
+
+const Babl * babl_trc_lookup_by_name_generic (const char *name);
+
+
+const Babl *
+babl_trc_new_generic (const char *name,
+ BablTRCType type,
+ double gamma,
+ int n_lut,
+ float *lut);
+
+void _babl_space_add_universal_rgb_generic (const Babl *space);
+void (*_babl_space_add_universal_rgb) (const Babl *space) =
+ _babl_space_add_universal_rgb_generic;
+
+const Babl *
+(*babl_trc_lookup_by_name) (const char *name) = babl_trc_lookup_by_name_generic;
+const Babl *
+(*babl_trc_new) (const char *name,
+ BablTRCType type,
+ double gamma,
+ int n_lut,
+ float *lut) = babl_trc_new_generic;
+
+#ifdef ARCH_X86_64
+void babl_base_init_x86_64_v2 (void);
+void babl_base_init_x86_64_v3 (void);
+void _babl_space_add_universal_rgb_x86_64_v2 (const Babl *space);
+void _babl_space_add_universal_rgb_x86_64_v3 (const Babl *space);
+
+const Babl *
+babl_trc_lookup_by_name_x86_64_v2 (const char *name);
+const Babl *
+babl_trc_lookup_by_name_x86_64_v3 (const char *name);
+
+const Babl *
+babl_trc_new_x86_64_v2 (const char *name,
+ BablTRCType type,
+ double gamma,
+ int n_lut,
+ float *lut);
+const Babl *
+babl_trc_new_x86_64_v3 (const char *name,
+ BablTRCType type,
+ double gamma,
+ int n_lut,
+ float *lut);
+
+#endif
+#ifdef ARCH_ARM
+void babl_base_init_arm_neon (void);
+void _babl_space_add_universal_rgb_arm_neon (const Babl *space);
+
+const Babl *
+babl_trc_lookup_by_name_arm_neon (const char *name);
+
+const Babl *
+babl_trc_new_arm_neon (const char *name,
+ BablTRCType type,
+ double gamma,
+ int n_lut,
+ float *lut);
+
+#endif
+
+static const char **simd_init (void)
+{
+ static const char *exclude[] = {"neon-", "x86-64-v3", "x86-64-v2", NULL};
+#ifdef ARCH_X86_64
+ BablCpuAccelFlags accel = babl_cpu_accel_get_support ();
+ if ((accel & BABL_CPU_ACCEL_X86_64_V3) == BABL_CPU_ACCEL_X86_64_V3)
+ {
+ static const char *exclude[] = {NULL};
+ babl_base_init = babl_base_init_x86_64_v2; /// !!
+ // this is correct,
+ // it performs better
+ // as observed in benchmarking
+ babl_trc_new = babl_trc_new_x86_64_v2;
+ babl_trc_lookup_by_name = babl_trc_lookup_by_name_x86_64_v2;
+ _babl_space_add_universal_rgb = _babl_space_add_universal_rgb_x86_64_v3;
+ return exclude;
+ }
+ else if ((accel & BABL_CPU_ACCEL_X86_64_V2) == BABL_CPU_ACCEL_X86_64_V2)
+ {
+ static const char *exclude[] = {"x86-64-v3-", NULL};
+ babl_base_init = babl_base_init_x86_64_v2;
+ babl_trc_new = babl_trc_new_x86_64_v2;
+ babl_trc_lookup_by_name = babl_trc_lookup_by_name_x86_64_v2;
+ _babl_space_add_universal_rgb = _babl_space_add_universal_rgb_x86_64_v2;
+ return exclude;
+ }
+ else
+ {
+ static const char *exclude[] = {"x86-64-v3-", "x86-64-v2-", NULL};
+ return exclude;
+ }
+#endif
+#ifdef ARCH_ARM
+ BablCpuAccelFlags accel = babl_cpu_accel_get_support ();
+ if ((accel & BABL_CPU_ACCEL_ARM_NEON) == BABL_CPU_ACCEL_ARM_NEON)
+ {
+ static const char *exclude[] = {NULL};
+ babl_base_init = babl_base_init_arm_neon;
+ babl_trc_new = babl_trc_new_arm_neon;
+ babl_trc_lookup_by_name = babl_trc_lookup_by_name_arm_neon;
+ _babl_space_add_universal_rgb = _babl_space_add_universal_rgb_arm_neon;
+ return exclude;
+ }
+ else
+ {
+ static const char *exclude[] = {"arm-neon-", NULL};
+ return exclude;
+ }
+#endif
+ return exclude;
+}
+
diff --git a/babl/babl.h b/babl/babl.h
index 4032faa..a9b47a3 100644
--- a/babl/babl.h
+++ b/babl/babl.h
@@ -636,6 +636,11 @@ void babl_space_get (const Babl *space,
* @blue_luminance: (out) (optional): Location for the blue luminance factor.
*
* Retrieve the relevant RGB luminance constants for a babl space.
+ *
+ * Note: these luminance coefficients should only ever be used on linear data.
+ * If your input @space is non-linear, you should convert your pixel values to
+ * the linearized variant of @space before making any computation with these
+ * coefficients. See #83.
*/
void
babl_space_get_rgb_luminance (const Babl *space,
@@ -713,6 +718,29 @@ const char * babl_format_get_encoding (const Babl *babl);
int babl_space_is_cmyk (const Babl *space);
int babl_space_is_gray (const Babl *space);
+typedef void (*BablFishProcess) (const Babl *babl, const char *src, char *dst, long n, void *data);
+/**
+ * babl_fish_get_process: (skip)
+ *
+ * get the dispatch function of a fish, this allows faster use of a fish
+ * in a loop than the more indirect method of babl_process, this also avoids
+ * base-level instrumentation.
+ */
+BablFishProcess babl_fish_get_process (const Babl *babl);
+
+
+/**
+ * babl_gc: (skip)
+ *
+ * Do a babl fish garbage collection cycle, should only be called
+ * from the main thread with no concurrent babl processing in other
+ * threads in paralell.
+ *
+ * Since: babl-0.1.98
+ */
+void babl_gc (void);
+
+
/* values below this are stored associated with this value, it should also be
* used as a generic alpha zero epsilon in GEGL to keep the threshold effects
* on one known value.
diff --git a/babl/babl/meson.build b/babl/babl/meson.build
new file mode 100644
index 0000000..461625a
--- /dev/null
+++ b/babl/babl/meson.build
@@ -0,0 +1,9 @@
+# Copy the public headers here for subproject builds.
+
+foreach _hdr : babl_headers
+ configure_file(
+ input: _hdr,
+ output: '@PLAINNAME@',
+ copy: true,
+ )
+endforeach
diff --git a/babl/base/babl-base.c b/babl/base/babl-base.c
index 1d93341..8b9cdde 100644
--- a/babl/base/babl-base.c
+++ b/babl/base/babl-base.c
@@ -25,19 +25,19 @@ static void types (void);
static void models (void);
void
-babl_base_init (void)
+BABL_SIMD_SUFFIX(babl_base_init) (void)
{
babl_hmpf_on_name_lookups++;
types ();
models ();
- babl_formats_init ();
+ BABL_SIMD_SUFFIX (babl_formats_init) ();
babl_hmpf_on_name_lookups--;
}
void
-babl_base_destroy (void)
+BABL_SIMD_SUFFIX(babl_base_destroy) (void)
{
/* done by the destruction of the elemental babl clases */
}
@@ -50,12 +50,12 @@ babl_base_destroy (void)
static void
types (void)
{
- babl_base_type_float ();
- babl_base_type_u15 ();
- babl_base_type_half ();
- babl_base_type_u8 ();
- babl_base_type_u16 ();
- babl_base_type_u32 ();
+ BABL_SIMD_SUFFIX (babl_base_type_float) ();
+ BABL_SIMD_SUFFIX (babl_base_type_u15) ();
+ BABL_SIMD_SUFFIX (babl_base_type_half) ();
+ BABL_SIMD_SUFFIX (babl_base_type_u8) ();
+ BABL_SIMD_SUFFIX (babl_base_type_u16) ();
+ BABL_SIMD_SUFFIX (babl_base_type_u32) ();
}
/*
@@ -67,9 +67,9 @@ static void
models (void)
{
babl_hmpf_on_name_lookups--;
- babl_base_model_rgb ();
- babl_base_model_gray ();
- babl_base_model_cmyk ();
+ BABL_SIMD_SUFFIX (babl_base_model_rgb) ();
+ BABL_SIMD_SUFFIX (babl_base_model_gray) ();
+ BABL_SIMD_SUFFIX (babl_base_model_cmyk) ();
babl_hmpf_on_name_lookups++;
- babl_base_model_ycbcr ();
+ BABL_SIMD_SUFFIX (babl_base_model_ycbcr) ();
}
diff --git a/babl/base/babl-base.h b/babl/base/babl-base.h
index 64f1667..291697b 100644
--- a/babl/base/babl-base.h
+++ b/babl/base/babl-base.h
@@ -19,22 +19,36 @@
#ifndef _BABL_BASE_H
#define _BABL_BASE_H
+#ifdef ARM_NEON
+#define BABL_SIMD_SUFFIX(symbol) symbol##_arm_neon
+#else
+#ifdef X86_64_V2
+#define BABL_SIMD_SUFFIX(symbol) symbol##_x86_64_v2
+#else
+#ifdef X86_64_V3
+#define BABL_SIMD_SUFFIX(symbol) symbol##_x86_64_v3
+#else
+#define BABL_SIMD_SUFFIX(symbol) symbol##_generic
+#endif
+#endif
+#endif
+
+extern void (*babl_base_init) (void);
-void babl_base_init (void);
-void babl_base_destroy (void);
-void babl_formats_init (void);
+void BABL_SIMD_SUFFIX(babl_base_init) (void);
+void BABL_SIMD_SUFFIX(babl_base_destroy) (void);
+void BABL_SIMD_SUFFIX(babl_formats_init) (void);
-void babl_base_type_half (void);
-void babl_base_type_float (void);
-void babl_base_type_u8 (void);
-void babl_base_type_u16 (void);
-void babl_base_type_u15 (void);
-void babl_base_type_u32 (void);
+void BABL_SIMD_SUFFIX(babl_base_type_half) (void);
+void BABL_SIMD_SUFFIX(babl_base_type_float) (void);
+void BABL_SIMD_SUFFIX(babl_base_type_u8) (void);
+void BABL_SIMD_SUFFIX(babl_base_type_u16) (void);
+void BABL_SIMD_SUFFIX(babl_base_type_u15) (void);
+void BABL_SIMD_SUFFIX(babl_base_type_u32) (void);
-void babl_base_model_pal (void);
-void babl_base_model_rgb (void);
-void babl_base_model_cmyk (void);
-void babl_base_model_gray (void);
-void babl_base_model_ycbcr (void);
+void BABL_SIMD_SUFFIX(babl_base_model_rgb) (void);
+void BABL_SIMD_SUFFIX(babl_base_model_cmyk) (void);
+void BABL_SIMD_SUFFIX(babl_base_model_gray) (void);
+void BABL_SIMD_SUFFIX(babl_base_model_ycbcr) (void);
#endif
diff --git a/babl/base/babl-rgb-converter.c b/babl/base/babl-rgb-converter.c
new file mode 100644
index 0000000..e0ba7c3
--- /dev/null
+++ b/babl/base/babl-rgb-converter.c
@@ -0,0 +1,536 @@
+#include "config.h"
+#include "babl-internal.h"
+#include "base/util.h"
+#include "babl-trc.h"
+#include "babl-base.h"
+
+static void
+prep_conversion (const Babl *babl)
+{
+ Babl *conversion = (void*) babl;
+ const Babl *source_space = babl_conversion_get_source_space (conversion);
+ float *matrixf;
+ unsigned int i;
+ float *lut_red;
+ float *lut_green;
+ float *lut_blue;
+
+ double matrix[9];
+ babl_matrix_mul_matrix (
+ (conversion->conversion.destination)->format.space->space.XYZtoRGB,
+ (conversion->conversion.source)->format.space->space.RGBtoXYZ,
+ matrix);
+
+ matrixf = babl_calloc (sizeof (float), 9 + 256 * 3); // we leak this matrix , which is a singleton
+ babl_matrix_to_float (matrix, matrixf);
+ conversion->conversion.data = matrixf;
+
+ lut_red = matrixf + 9;
+ lut_green = lut_red + 256;
+ lut_blue = lut_green + 256;
+ for (i = 0; i < 256; i++)
+ {
+ lut_red[i] = babl_trc_to_linear (source_space->space.trc[0], i/255.0);
+ lut_green[i] = babl_trc_to_linear (source_space->space.trc[1], i/255.0);
+ lut_blue[i] = babl_trc_to_linear (source_space->space.trc[2], i/255.0);
+ }
+}
+
+#define TRC_IN(rgba_in, rgba_out) do{ int i;\
+ for (i = 0; i < samples; i++) \
+ { \
+ rgba_out[i*4+3] = rgba_in[i*4+3]; \
+ } \
+ if ((source_space->space.trc[0] == source_space->space.trc[1]) && \
+ (source_space->space.trc[1] == source_space->space.trc[2])) \
+ { \
+ const Babl *trc = (void*)source_space->space.trc[0]; \
+ babl_trc_to_linear_buf(trc, rgba_in, rgba_out, 4, 4, 3, samples); \
+ } \
+ else \
+ { \
+ unsigned int c; \
+ for (c = 0; c < 3; c ++) \
+ { \
+ const Babl *trc = (void*)source_space->space.trc[c]; \
+ babl_trc_to_linear_buf(trc, rgba_in + c, rgba_out + c, 4, 4, 1, samples); \
+ } \
+ } \
+}while(0)
+
+#define TRC_OUT(rgba_in, rgba_out) do{\
+ { \
+ if ((destination_space->space.trc[0] == destination_space->space.trc[1]) && \
+ (destination_space->space.trc[1] == destination_space->space.trc[2])) \
+ { \
+ const Babl *trc = (void*)destination_space->space.trc[0]; \
+ babl_trc_from_linear_buf(trc, rgba_in, rgba_out, 4, 4, 3, samples); \
+ } \
+ else \
+ { \
+ unsigned int c; \
+ for (c = 0; c < 3; c ++) \
+ { \
+ const Babl *trc = (void*)destination_space->space.trc[c]; \
+ babl_trc_from_linear_buf(trc, rgba_in + c, rgba_out + c, 4, 4, 1, samples); \
+ } \
+ } \
+ }\
+} while(0)
+
+
+static inline void
+universal_nonlinear_rgba_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *source_space = babl_conversion_get_source_space (conversion);
+ const Babl *destination_space = babl_conversion_get_destination_space (conversion);
+
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ TRC_IN(rgba_in, rgba_out);
+
+ babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
+
+ TRC_OUT(rgba_out, rgba_out);
+}
+
+static inline void
+universal_nonlinear_rgb_linear_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *source_space = babl_conversion_get_source_space (conversion);
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ TRC_IN(rgba_in, rgba_out);
+
+ babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
+}
+
+static inline void
+universal_linear_rgb_nonlinear_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *destination_space = conversion->conversion.destination->format.space;
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples);
+
+ TRC_OUT(rgba_out, rgba_out);
+}
+
+static inline void
+universal_rgba_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ float *matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf4 (matrixf, rgba_in, rgba_out, samples);
+}
+
+static inline void
+universal_rgb_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ float *matrixf = data;
+ float *rgb_in = (void*)src_char;
+ float *rgb_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf3 (matrixf, rgb_in, rgb_out, samples);
+}
+
+
+static inline void
+universal_ya_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ memcpy (dst_char, src_char, samples * 4 * 2);
+}
+
+static inline void
+universal_y_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ memcpy (dst_char, src_char, samples * 4);
+}
+
+
+static inline void
+universal_nonlinear_rgb_u8_converter (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *destination_space = conversion->conversion.destination->format.space;
+
+ float * matrixf = data;
+ float * in_trc_lut_red = matrixf + 9;
+ float * in_trc_lut_green = in_trc_lut_red + 256;
+ float * in_trc_lut_blue = in_trc_lut_green + 256;
+ unsigned int i;
+ uint8_t *rgb_in_u8 = (void*)src_char;
+ uint8_t *rgb_out_u8 = (void*)dst_char;
+
+ float rgba_out[4*samples];
+
+ for (i = 0; i < samples; i++)
+ {
+ rgba_out[i*4+0]=in_trc_lut_red[rgb_in_u8[i*3+0]];
+ rgba_out[i*4+1]=in_trc_lut_green[rgb_in_u8[i*3+1]];
+ rgba_out[i*4+2]=in_trc_lut_blue[rgb_in_u8[i*3+2]];
+ rgba_out[i*4+3]=rgb_in_u8[i*3+2] * 255.0f;
+ }
+
+ babl_matrix_mul_vectorff_buf4 (matrixf, rgba_out, rgba_out, samples);
+
+ {
+ TRC_OUT(rgba_out, rgba_out);
+
+ for (i = 0; i < samples; i++)
+ for (unsigned int c = 0; c < 3; c ++)
+ rgb_out_u8[i*3+c] = rgba_out[i*4+c] * 255.0f;
+ }
+
+}
+
+
+#if defined(USE_SSE2)
+
+#define m(matr, j, i) matr[j*3+i]
+
+#include <emmintrin.h>
+
+static inline void babl_matrix_mul_vectorff_buf4_sse2 (const float *mat,
+ const float *v_in,
+ float *v_out,
+ unsigned int samples)
+{
+ const __v4sf m___0 = {m(mat, 0, 0), m(mat, 1, 0), m(mat, 2, 0), 0};
+ const __v4sf m___1 = {m(mat, 0, 1), m(mat, 1, 1), m(mat, 2, 1), 0};
+ const __v4sf m___2 = {m(mat, 0, 2), m(mat, 1, 2), m(mat, 2, 2), 1};
+ unsigned int i;
+ for (i = 0; i < samples; i ++)
+ {
+ __v4sf a, b, c = _mm_load_ps(&v_in[0]);
+ a = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(0,0,0,0));
+ b = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(1,1,1,1));
+ c = (__v4sf) _mm_shuffle_epi32((__m128i)c, _MM_SHUFFLE(3,2,2,2));
+ _mm_store_ps (v_out, m___0 * a + m___1 * b + m___2 * c);
+ v_out += 4;
+ v_in += 4;
+ }
+ _mm_empty ();
+}
+
+#undef m
+
+static inline void
+universal_nonlinear_rgba_converter_sse2 (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *source_space = babl_conversion_get_source_space (conversion);
+ const Babl *destination_space = babl_conversion_get_destination_space (conversion);
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ TRC_IN(rgba_in, rgba_out);
+
+ babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
+
+ TRC_OUT(rgba_out, rgba_out);
+}
+
+
+static inline void
+universal_rgba_converter_sse2 (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ float *matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples);
+}
+
+static inline void
+universal_nonlinear_rgb_u8_converter_sse2 (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *destination_space = conversion->conversion.destination->format.space;
+
+ float * matrixf = data;
+ float * in_trc_lut_red = matrixf + 9;
+ float * in_trc_lut_green = in_trc_lut_red + 256;
+ float * in_trc_lut_blue = in_trc_lut_green + 256;
+ unsigned int i;
+ uint8_t *rgb_in_u8 = (void*)src_char;
+ uint8_t *rgb_out_u8 = (void*)dst_char;
+
+ // The alignment is necessary for SIMD intrinsics in babl_matrix_mul_vectorff_buf4_sse2()
+ float __attribute__ ((aligned (16))) rgba_out[4*samples];
+
+ for (i = 0; i < samples; i++)
+ {
+ rgba_out[i*4+0]=in_trc_lut_red[rgb_in_u8[i*3+0]];
+ rgba_out[i*4+1]=in_trc_lut_green[rgb_in_u8[i*3+1]];
+ rgba_out[i*4+2]=in_trc_lut_blue[rgb_in_u8[i*3+2]];
+ }
+
+ babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
+
+ {
+ TRC_OUT(rgba_out, rgba_out);
+
+ for (i = 0; i < samples; i++)
+ for (unsigned c = 0; c < 3; c ++)
+ rgb_out_u8[i*3+c] = rgba_out[i*4+c] * 255 + 0.5f;
+ }
+}
+
+
+static inline void
+universal_nonlinear_rgb_linear_converter_sse2 (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *source_space = babl_conversion_get_source_space (conversion);
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ TRC_IN(rgba_in, rgba_out);
+
+ babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_out, rgba_out, samples);
+}
+
+
+static inline void
+universal_linear_rgb_nonlinear_converter_sse2 (const Babl *conversion,
+ unsigned char *__restrict__ src_char,
+ unsigned char *__restrict__ dst_char,
+ long samples,
+ void *data)
+{
+ const Babl *destination_space = conversion->conversion.destination->format.space;
+ float * matrixf = data;
+ float *rgba_in = (void*)src_char;
+ float *rgba_out = (void*)dst_char;
+
+ babl_matrix_mul_vectorff_buf4_sse2 (matrixf, rgba_in, rgba_out, samples);
+
+ TRC_OUT(rgba_out, rgba_out);
+}
+#endif
+
+
+static int
+add_rgb_adapter (Babl *babl,
+ void *space)
+{
+ if (babl != space)
+ {
+
+#if defined(USE_SSE2)
+ if ((babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE) &&
+ (babl_cpu_accel_get_support () & BABL_CPU_ACCEL_X86_SSE2))
+ {
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", space),
+ babl_format_with_space("RGBA float", babl),
+ "linear", universal_rgba_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", babl),
+ babl_format_with_space("RGBA float", space),
+ "linear", universal_rgba_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", space),
+ babl_format_with_space("R'G'B'A float", babl),
+ "linear", universal_nonlinear_rgba_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", babl),
+ babl_format_with_space("R'G'B'A float", space),
+ "linear", universal_nonlinear_rgba_converter_sse2,
+ NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", space),
+ babl_format_with_space("RGBA float", babl),
+ "linear", universal_nonlinear_rgb_linear_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", babl),
+ babl_format_with_space("RGBA float", space),
+ "linear", universal_nonlinear_rgb_linear_converter_sse2,
+ NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", babl),
+ babl_format_with_space("R'G'B'A float", space),
+ "linear", universal_linear_rgb_nonlinear_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", space),
+ babl_format_with_space("R'G'B'A float", babl),
+ "linear", universal_linear_rgb_nonlinear_converter_sse2,
+ NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B' u8", space),
+ babl_format_with_space("R'G'B' u8", babl),
+ "linear", universal_nonlinear_rgb_u8_converter_sse2,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B' u8", babl),
+ babl_format_with_space("R'G'B' u8", space),
+ "linear", universal_nonlinear_rgb_u8_converter_sse2,
+ NULL));
+ }
+ else
+#endif
+ {
+#if 1
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", space),
+ babl_format_with_space("RGBA float", babl),
+ "linear", universal_rgba_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", babl),
+ babl_format_with_space("RGBA float", space),
+ "linear", universal_rgba_converter,
+ NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", space),
+ babl_format_with_space("R'G'B'A float", babl),
+ "linear", universal_nonlinear_rgba_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", babl),
+ babl_format_with_space("R'G'B'A float", space),
+ "linear", universal_nonlinear_rgba_converter,
+ NULL));
+#endif
+#if 1
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", space),
+ babl_format_with_space("RGBA float", babl),
+ "linear", universal_nonlinear_rgb_linear_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B'A float", babl),
+ babl_format_with_space("RGBA float", space),
+ "linear", universal_nonlinear_rgb_linear_converter,
+ NULL));
+#endif
+
+#if 1
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B' u8", space),
+ babl_format_with_space("R'G'B' u8", babl),
+ "linear", universal_nonlinear_rgb_u8_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("R'G'B' u8", babl),
+ babl_format_with_space("R'G'B' u8", space),
+ "linear", universal_nonlinear_rgb_u8_converter,
+ NULL));
+
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", babl),
+ babl_format_with_space("R'G'B'A float", space),
+ "linear", universal_linear_rgb_nonlinear_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGBA float", space),
+ babl_format_with_space("R'G'B'A float", babl),
+ "linear", universal_linear_rgb_nonlinear_converter,
+ NULL));
+#endif
+ }
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGB float", space),
+ babl_format_with_space("RGB float", babl),
+ "linear", universal_rgb_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("RGB float", babl),
+ babl_format_with_space("RGB float", space),
+ "linear", universal_rgb_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("Y float", space),
+ babl_format_with_space("Y float", babl),
+ "linear", universal_y_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("YaA float", babl),
+ babl_format_with_space("YaA float", space),
+ "linear", universal_ya_converter,
+ NULL));
+ prep_conversion(babl_conversion_new(
+ babl_format_with_space("YA float", babl),
+ babl_format_with_space("YA float", space),
+ "linear", universal_ya_converter,
+ NULL));
+ }
+ return 0;
+}
+
+/* The first time a new Babl space is used - for creation of a fish, is when
+ * this function is called, it adds conversions hooks that provides its formats
+ * with conversions internally as well as for conversions to and from other RGB
+ * spaces.
+ */
+void
+BABL_SIMD_SUFFIX(_babl_space_add_universal_rgb) (const Babl *space);
+void
+BABL_SIMD_SUFFIX(_babl_space_add_universal_rgb) (const Babl *space)
+{
+ babl_space_class_for_each (add_rgb_adapter, (void*)space);
+}
diff --git a/babl/babl-trc.c b/babl/base/babl-trc.c
index e76bb92..09beb07 100644
--- a/babl/babl-trc.c
+++ b/babl/base/babl-trc.c
@@ -26,6 +26,7 @@
#include "config.h"
#include "babl-internal.h"
+#include "babl-base.h"
#include "base/util.h"
static BablTRC trc_db[MAX_TRCS];
@@ -51,13 +52,13 @@ babl_trc_lut_from_linear (const Babl *trc_,
if (entry >= trc->lut_size -1)
{
entry = trc->lut_size - 1;
- diff = 0.0;
+ diff = 0.0f;
}
else if (entry < 0) entry = 0;
- if (diff > 0.0)
+ if (diff > 0.0f)
{
- ret = trc->inv_lut[entry] * (1.0 - diff) + trc->inv_lut[entry+1] * diff;
+ ret = trc->inv_lut[entry] * (1.0f - diff) + trc->inv_lut[entry+1] * diff;
}
else
{
@@ -80,9 +81,9 @@ babl_trc_lut_to_linear (const Babl *trc_,
if (entry >= trc->lut_size) entry = trc->lut_size - 1;
else if (entry < 0) entry = 0;
- if (diff > 0.0 && entry < trc->lut_size - 1)
+ if (diff > 0.0f && entry < trc->lut_size - 1)
{
- ret = trc->lut[entry] * (1.0 - diff) + trc->lut[entry+1] * diff;
+ ret = trc->lut[entry] * (1.0f - diff) + trc->lut[entry+1] * diff;
}
else
{
@@ -127,32 +128,48 @@ _babl_trc_gamma_from_linear (const Babl *trc_,
static inline void
_babl_trc_gamma_to_linear_buf (const Babl *trc_,
- const float *in,
- float *out,
+ const float *__restrict__ in,
+ float *__restrict__ out,
int in_gap,
int out_gap,
int components,
int count)
{
- int i, c;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c ++)
- out[out_gap * i + c] = _babl_trc_gamma_to_linear (trc_, in[in_gap *i + c]);
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c ++)
+ out[4 * i + c] = _babl_trc_gamma_to_linear (trc_, in[4 *i + c]);
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c ++)
+ out[out_gap * i + c] = _babl_trc_gamma_to_linear (trc_, in[in_gap *i + c]);
+ }
}
static inline void
_babl_trc_gamma_from_linear_buf (const Babl *trc_,
- const float *in,
- float *out,
+ const float *__restrict__ in,
+ float *__restrict__ out,
int in_gap,
int out_gap,
int components,
int count)
{
- int i, c;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c ++)
- out[out_gap * i + c] = _babl_trc_gamma_from_linear (trc_, in[in_gap *i + c]);
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c ++)
+ out[4 * i + c] = _babl_trc_gamma_from_linear (trc_, in[4 *i + c]);
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c ++)
+ out[out_gap * i + c] = _babl_trc_gamma_from_linear (trc_, in[in_gap *i + c]);
+ }
}
static inline float
@@ -165,17 +182,20 @@ _babl_trc_formula_srgb_from_linear (const Babl *trc_,
float b = trc->lut[2];
float c = trc->lut[3];
float d = trc->lut[4];
- if (x > c * d) // XXX: verify that this math is the correct inverse
+ float e = trc->lut[5];
+ float f = trc->lut[6];
+
+ if (x - f > c * d) // XXX: verify that this math is the correct inverse
{
- float v = _babl_trc_gamma_from_linear ((Babl *) trc, x);
+ float v = _babl_trc_gamma_from_linear ((Babl *) trc, x - f);
v = (v-b)/a;
- if (v < 0.0 || v >= 0.0)
+ if (v < 0.0f || v >= 0.0f)
return v;
- return 0.0;
+ return 0.0f;
}
- if (c > 0.0)
- return x / c;
- return 0.0;
+ if (c > 0.0f)
+ return (x - e) / c;
+ return 0.0f;
}
static inline float
@@ -188,15 +208,55 @@ _babl_trc_formula_srgb_to_linear (const Babl *trc_,
float b = trc->lut[2];
float c = trc->lut[3];
float d = trc->lut[4];
+ float e = trc->lut[5];
+ float f = trc->lut[6];
+
+ if (x >= d) // OPT can be reduced to be branchless
+ {
+ return _babl_trc_gamma_to_linear ((Babl *) trc, a * x + b) + e;
+ }
+ return c * x + f;
+}
+static inline float
+_babl_trc_formula_cie_from_linear (const Babl *trc_,
+ float value)
+{
+ BablTRC *trc = (void*)trc_;
+ float x= value;
+ float a = trc->lut[1];
+ float b = trc->lut[2];
+ float c = trc->lut[3];
- if (x >= d)
+ if (x > c)
{
- return _babl_trc_gamma_to_linear ((Babl *) trc, a * x + b);
+ float v = _babl_trc_gamma_from_linear ((Babl *) trc, x - c);
+ v = (v-b)/a;
+ if (v < 0.0f || v >= 0.0f)
+ return v;
}
- return c * x;
+ return 0.0f;
}
static inline float
+_babl_trc_formula_cie_to_linear (const Babl *trc_,
+ float value)
+{
+ BablTRC *trc = (void*)trc_;
+ float x= value;
+ float a = trc->lut[1];
+ float b = trc->lut[2];
+ float c = trc->lut[3];
+
+ if (x >= -b / a)
+ {
+ return _babl_trc_gamma_to_linear ((Babl *) trc, a * x + b) + c;
+ }
+ return c;
+}
+
+
+
+static inline float
_babl_trc_srgb_to_linear (const Babl *trc_,
float value)
{
@@ -219,10 +279,18 @@ _babl_trc_srgb_to_linear_buf (const Babl *trc_,
int components,
int count)
{
- int i, c;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c++)
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c++)
+ out[4 * i + c] = babl_gamma_2_2_to_linearf (in[4 * i + c]);
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c++)
out[out_gap * i + c] = babl_gamma_2_2_to_linearf (in[in_gap * i + c]);
+ }
}
static inline void
@@ -234,61 +302,97 @@ _babl_trc_srgb_from_linear_buf (const Babl *trc_,
int components,
int count)
{
- int i, c;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c++)
- out[out_gap * i + c] = babl_linear_to_gamma_2_2f (in[in_gap * i + c]);
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c++)
+ out[4 * i + c] = babl_linear_to_gamma_2_2f (in[4 * i + c]);
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c++)
+ out[out_gap * i + c] = babl_linear_to_gamma_2_2f (in[in_gap * i + c]);
+ }
}
static inline void
_babl_trc_to_linear_buf_generic (const Babl *trc_,
- const float *in,
- float *out,
+ const float *__restrict__ in,
+ float *__restrict__ out,
int in_gap,
int out_gap,
int components,
int count)
{
- int i, c;
BablTRC *trc = (void*)trc_;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c ++)
- out[out_gap * i + c] = trc->fun_to_linear (trc_, in[in_gap * i + c]);
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c ++)
+ out[4 * i + c] = trc->fun_to_linear (trc_, in[4 * i + c]);
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c ++)
+ out[out_gap * i + c] = trc->fun_to_linear (trc_, in[in_gap * i + c]);
+ }
}
static inline void
_babl_trc_from_linear_buf_generic (const Babl *trc_,
- const float *in,
- float *out,
+ const float *__restrict__ in,
+ float *__restrict__ out,
int in_gap,
int out_gap,
int components,
int count)
{
- int i, c;
BablTRC *trc = (void*)trc_;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c ++)
- out[out_gap * i + c] = trc->fun_from_linear (trc_, in[in_gap * i + c]);
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c ++)
+ out[4 * i + c] = trc->fun_from_linear (trc_, in[4 * i + c]);
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c ++)
+ out[out_gap * i + c] = trc->fun_from_linear (trc_, in[in_gap * i + c]);
+ }
}
+
+
static inline void _babl_trc_linear_buf (const Babl *trc_,
- const float *in,
- float *out,
+ const float *__restrict__ in,
+ float *__restrict__ out,
int in_gap,
int out_gap,
int components,
int count)
{
- int i, c;
- for (i = 0; i < count; i ++)
- for (c = 0; c < components; c ++)
- out[i * out_gap + c] = in[i * in_gap + c];
+ if (in_gap == out_gap && in_gap == 4 && components == 3)
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < 3; c ++)
+ out[i * 4 + c] = in[i * 4 + c];
+ }
+ else
+ {
+ for (int i = 0; i < count; i ++)
+ for (int c = 0; c < components; c ++)
+ out[i * out_gap + c] = in[i * in_gap + c];
+ }
}
+const Babl *
+BABL_SIMD_SUFFIX (babl_trc_lookup_by_name) (const char *name);
const Babl *
-babl_trc (const char *name)
+BABL_SIMD_SUFFIX (babl_trc_lookup_by_name) (const char *name)
{
int i;
for (i = 0; trc_db[i].instance.class_type; i++)
@@ -301,7 +405,14 @@ babl_trc (const char *name)
}
const Babl *
-babl_trc_new (const char *name,
+BABL_SIMD_SUFFIX (babl_trc_new) (const char *name,
+ BablTRCType type,
+ double gamma,
+ int n_lut,
+ float *lut);
+
+const Babl *
+BABL_SIMD_SUFFIX (babl_trc_new) (const char *name,
BablTRCType type,
double gamma,
int n_lut,
@@ -368,7 +479,7 @@ babl_trc_new (const char *name,
for (k = 0; k < 16; k++)
{
double guess = (min + max) / 2;
- float reversed_index = babl_trc_lut_to_linear (BABL(&trc_db[i]), guess) * (n_lut-1.0);
+ float reversed_index = babl_trc_lut_to_linear (BABL(&trc_db[i]), guess) * (n_lut-1.0f);
if (reversed_index < j)
{
@@ -416,11 +527,38 @@ babl_trc_new (const char *name,
trc_db[i].poly_gamma_from_linear_x1,
POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE);
break;
+ case BABL_TRC_FORMULA_CIE:
+ trc_db[i].lut = babl_calloc (sizeof (float), 4);
+ {
+ int j;
+ for (j = 0; j < 4; j++)
+ trc_db[i].lut[j] = lut[j];
+ }
+ trc_db[i].fun_to_linear = _babl_trc_formula_cie_to_linear;
+ trc_db[i].fun_from_linear = _babl_trc_formula_cie_from_linear;
+
+ trc_db[i].poly_gamma_to_linear_x0 = lut[4];
+ trc_db[i].poly_gamma_to_linear_x1 = POLY_GAMMA_X1;
+ babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_to_linear,
+ trc_db[i].gamma,
+ trc_db[i].poly_gamma_to_linear_x0,
+ trc_db[i].poly_gamma_to_linear_x1,
+ POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE);
+
+ trc_db[i].poly_gamma_from_linear_x0 = lut[3] * lut[4];
+ trc_db[i].poly_gamma_from_linear_x1 = POLY_GAMMA_X1;
+ babl_polynomial_approximate_gamma (&trc_db[i].poly_gamma_from_linear,
+ trc_db[i].rgamma,
+ trc_db[i].poly_gamma_from_linear_x0,
+ trc_db[i].poly_gamma_from_linear_x1,
+ POLY_GAMMA_DEGREE, POLY_GAMMA_SCALE);
+ break;
+
case BABL_TRC_FORMULA_SRGB:
- trc_db[i].lut = babl_calloc (sizeof (float), 5);
+ trc_db[i].lut = babl_calloc (sizeof (float), 7);
{
int j;
- for (j = 0; j < 5; j++)
+ for (j = 0; j < 7; j++)
trc_db[i].lut[j] = lut[j];
}
trc_db[i].fun_to_linear = _babl_trc_formula_srgb_to_linear;
@@ -456,17 +594,13 @@ babl_trc_new (const char *name,
return (Babl*)&trc_db[i];
}
-const Babl *
-babl_trc_lut (const char *name,
- int n,
- float *entries)
-{
- return babl_trc_new (name, BABL_TRC_LUT, 0, n, entries);
-}
+void
+BABL_SIMD_SUFFIX(babl_trc_class_for_each) (BablEachFunction each_fun,
+ void *user_data);
void
-babl_trc_class_for_each (BablEachFunction each_fun,
- void *user_data)
+BABL_SIMD_SUFFIX(babl_trc_class_for_each) (BablEachFunction each_fun,
+ void *user_data)
{
int i=0;
for (i = 0; trc_db[i].instance.class_type; i++)
@@ -474,141 +608,3 @@ babl_trc_class_for_each (BablEachFunction each_fun,
return;
}
-const Babl *
-babl_trc_formula_srgb (double g,
- double a,
- double b,
- double c,
- double d)
-{
- char name[128];
- int i;
- float params[5]={g, a, b, c, d};
-
- if (fabs (g - 2.400) < 0.01 &&
- fabs (a - 0.947) < 0.01 &&
- fabs (b - 0.052) < 0.01 &&
- fabs (c - 0.077) < 0.01 &&
- fabs (d - 0.040) < 0.01)
- return babl_trc ("sRGB");
-
- snprintf (name, sizeof (name), "%.6f %.6f %.4f %.4f %.4f", g, a, b, c, d);
- for (i = 0; name[i]; i++)
- if (name[i] == ',') name[i] = '.';
- while (name[strlen(name)-1]=='0')
- name[strlen(name)-1]='\0';
- return babl_trc_new (name, BABL_TRC_FORMULA_SRGB, g, 0, params);
-}
-
-const Babl *
-babl_trc_gamma (double gamma)
-{
- char name[32];
- int i;
- if (fabs (gamma - 1.0) < 0.01)
- return babl_trc_new ("linear", BABL_TRC_LINEAR, 1.0, 0, NULL);
-
- snprintf (name, sizeof (name), "%.6f", gamma);
- for (i = 0; name[i]; i++)
- if (name[i] == ',') name[i] = '.';
- while (name[strlen(name)-1]=='0')
- name[strlen(name)-1]='\0';
- return babl_trc_new (name, BABL_TRC_FORMULA_GAMMA, gamma, 0, NULL);
-}
-
-void
-babl_trc_class_init (void)
-{
- babl_trc_new ("sRGB", BABL_TRC_SRGB, 2.2, 0, NULL);
- babl_trc_gamma (2.2);
- babl_trc_gamma (1.8);
- babl_trc_gamma (1.0);
- babl_trc_new ("linear", BABL_TRC_LINEAR, 1.0, 0, NULL);
-}
-
-#if 0
-float
-babl_trc_from_linear (const Babl *trc_,
- float value)
-{
- return babl_trc_from_linear (trc_, value);
-}
-
-float
-babl_trc_to_linear (const Babl *trc_,
- float value)
-{
- return babl_trc_to_linear (trc_, value);
-}
-#endif
-
-static int
-babl_lut_match_gamma (float *lut,
- int lut_size,
- float gamma)
-{
- int match = 1;
- int i;
- if (lut_size > 1024)
- {
- for (i = 0; match && i < lut_size; i++)
- {
- if (fabs (lut[i] - pow ((i / (lut_size-1.0)), gamma)) > 0.0001)
- match = 0;
- }
- }
- else
- {
- for (i = 0; match && i < lut_size; i++)
- {
- if (fabs (lut[i] - pow ((i / (lut_size-1.0)), gamma)) > 0.001)
- match = 0;
- }
- }
- return match;
-}
-
-const Babl *
-babl_trc_lut_find (float *lut,
- int lut_size)
-{
- int i;
- int match = 1;
-
- /* look for linear match */
- for (i = 0; match && i < lut_size; i++)
- if (fabs (lut[i] - i / (lut_size-1.0)) > 0.015)
- match = 0;
- if (match)
- return babl_trc_gamma (1.0);
-
- /* look for sRGB match: */
- match = 1;
- if (lut_size > 1024)
- {
- for (i = 0; match && i < lut_size; i++)
- {
- if (fabs (lut[i] - gamma_2_2_to_linear (i / (lut_size-1.0))) > 0.0001)
- match = 0;
- }
- }
- else
- {
- for (i = 0; match && i < lut_size; i++)
- {
- if (fabs (lut[i] - gamma_2_2_to_linear (i / (lut_size-1.0))) > 0.001)
- match = 0;
- }
- }
- if (match)
- return babl_trc ("sRGB");
-
- if (babl_lut_match_gamma (lut, lut_size, 2.2))
- return babl_trc_gamma(2.2);
-
- if (babl_lut_match_gamma (lut, lut_size, 1.8))
- return babl_trc_gamma(1.8);
-
- return NULL;
-}
-
diff --git a/babl/babl-trc.h b/babl/base/babl-trc.h
index 380a736..1901fd2 100644
--- a/babl/babl-trc.h
+++ b/babl/base/babl-trc.h
@@ -30,7 +30,8 @@ typedef enum {BABL_TRC_LINEAR,
BABL_TRC_FORMULA_GAMMA,
BABL_TRC_SRGB,
BABL_TRC_FORMULA_SRGB,
- BABL_TRC_LUT}
+ BABL_TRC_LUT,
+ BABL_TRC_FORMULA_CIE}
BablTRCType;
typedef struct
@@ -66,6 +67,8 @@ typedef struct
float *lut;
float *inv_lut;
char name[128];
+ int valid_u8_lut;
+ float u8_lut[256];
} BablTRC;
static inline void babl_trc_from_linear_buf (const Babl *trc_,
@@ -101,6 +104,7 @@ static inline float babl_trc_to_linear (const Babl *trc_, float value)
}
void
-babl_trc_class_init (void);
+babl_trc_class_init_generic (void);
+
#endif
diff --git a/babl/base/formats.c b/babl/base/formats.c
index bad9d14..03488c4 100644
--- a/babl/base/formats.c
+++ b/babl/base/formats.c
@@ -25,7 +25,7 @@
#include "babl-base.h"
void
-babl_formats_init (void)
+BABL_SIMD_SUFFIX (babl_formats_init) (void)
{
const Babl *types[]={
babl_type_from_id (BABL_DOUBLE),
@@ -35,7 +35,7 @@ babl_formats_init (void)
babl_type_from_id (BABL_U16),
babl_type_from_id (BABL_U32)
};
- for (int i = 0; i < sizeof (types)/sizeof(types[0]);i++)
+ for (size_t i = 0; i < sizeof (types) / sizeof(types[0]); i++)
{
const Babl *type = types[i];
diff --git a/babl/base/meson.build b/babl/base/meson.build
index a78fd84..e59609c 100644
--- a/babl/base/meson.build
+++ b/babl/base/meson.build
@@ -14,10 +14,43 @@ babl_base_sources = [
'type-u16.c',
'type-u32.c',
'type-u8.c',
+ 'babl-trc.c',
+ 'babl-rgb-converter.c',
]
babl_base = static_library('babl_base',
babl_base_sources,
include_directories: [rootInclude, bablInclude],
dependencies: [math, lcms],
-)
+ c_args: common_c_flags + [sse2_cflags]
+)
+
+if host_cpu_family == 'x86_64'
+
+ babl_base_x86_64_v2 = static_library('babl_base-x86-64-v2',
+ babl_base_sources,
+ include_directories: [rootInclude, bablInclude],
+ dependencies: [math, lcms],
+ c_args: common_c_flags + x86_64_v2_flags
+ )
+
+ babl_base_x86_64_v3 = static_library('babl_base-x86-64-v3',
+ babl_base_sources,
+ include_directories: [rootInclude, bablInclude],
+ dependencies: [math, lcms],
+ c_args: common_c_flags + x86_64_v3_flags
+ )
+
+endif
+
+
+if host_cpu_family == 'arm'
+
+ babl_base_arm_neon = static_library('babl_base-arm-neon',
+ babl_base_sources,
+ include_directories: [rootInclude, bablInclude],
+ dependencies: [math, lcms],
+ c_args: common_c_flags + arm_neon_flags
+ )
+
+endif
diff --git a/babl/base/model-cmyk.c b/babl/base/model-cmyk.c
index 13fdedf..1fa02be 100644
--- a/babl/base/model-cmyk.c
+++ b/babl/base/model-cmyk.c
@@ -613,7 +613,7 @@ cmy_to_rgba (const Babl *conversion,
#endif
void
-babl_base_model_cmyk (void)
+BABL_SIMD_SUFFIX (babl_base_model_cmyk) (void)
{
babl_component_new ("cyan", NULL);
babl_component_new ("yellow", NULL);
diff --git a/babl/base/model-gray.c b/babl/base/model-gray.c
index 3862400..7441baa 100644
--- a/babl/base/model-gray.c
+++ b/babl/base/model-gray.c
@@ -31,7 +31,7 @@ static void formats (void);
static void init_single_precision (void);
void
-babl_base_model_gray (void)
+BABL_SIMD_SUFFIX (babl_base_model_gray) (void)
{
components ();
models ();
@@ -90,7 +90,6 @@ models (void)
"linear",
NULL);
-
babl_model_new (
"id", BABL_GRAY_ALPHA,
babl_component_from_id (BABL_GRAY_LINEAR),
diff --git a/babl/base/model-rgb.c b/babl/base/model-rgb.c
index a3064ef..824665a 100644
--- a/babl/base/model-rgb.c
+++ b/babl/base/model-rgb.c
@@ -32,7 +32,7 @@ static void formats (void);
static void init_single_precision (void);
void
-babl_base_model_rgb (void)
+BABL_SIMD_SUFFIX (babl_base_model_rgb) (void)
{
components ();
models ();
diff --git a/babl/base/model-ycbcr.c b/babl/base/model-ycbcr.c
index 64db6a2..e061298 100644
--- a/babl/base/model-ycbcr.c
+++ b/babl/base/model-ycbcr.c
@@ -34,7 +34,7 @@ static void conversions (void);
static void formats (void);
void
-babl_base_model_ycbcr (void)
+BABL_SIMD_SUFFIX (babl_base_model_ycbcr) (void)
{
components ();
models ();
diff --git a/babl/base/pow-24.h b/babl/base/pow-24.h
index ecd1282..98e2374 100644
--- a/babl/base/pow-24.h
+++ b/babl/base/pow-24.h
@@ -98,7 +98,7 @@ static inline float babl_frexpf(float x, int *e)
if (!ee) {
if (x) {
- x = babl_frexpf(x*18446744073709551616.0, e);
+ x = babl_frexpf(x*18446744073709551616.0f, e);
*e -= 64;
} else *e = 0;
return x;
@@ -130,11 +130,12 @@ static inline float babl_frexpf(float x, int *e)
static inline float
init_newtonf (float x, float exponent, float c0, float c1, float c2)
{
+#define fM_LN2 0.69314718055994530942f
int iexp = 0;
float y = babl_frexpf(x, &iexp);
y = 2*y+(iexp-2);
- c1 *= M_LN2*exponent;
- c2 *= M_LN2*M_LN2*exponent*exponent;
+ c1 *= fM_LN2*exponent;
+ c2 *= fM_LN2*fM_LN2*exponent*exponent;
return y = c0 + c1*y + c2*y*y;
}
diff --git a/babl/base/type-float.c b/babl/base/type-float.c
index 5b03b3f..9517831 100644
--- a/babl/base/type-float.c
+++ b/babl/base/type-float.c
@@ -83,7 +83,7 @@ convert_float_float (const Babl *babl,
void
-babl_base_type_float (void)
+BABL_SIMD_SUFFIX (babl_base_type_float) (void)
{
babl_type_new (
"float",
diff --git a/babl/base/type-half.c b/babl/base/type-half.c
index 862d662..a146185 100644
--- a/babl/base/type-half.c
+++ b/babl/base/type-half.c
@@ -395,7 +395,7 @@ convert_half_float (BablConversion *conversion,
void
-babl_base_type_half (void)
+BABL_SIMD_SUFFIX (babl_base_type_half) (void)
{
babl_type_new (
"half",
diff --git a/babl/base/type-u15.c b/babl/base/type-u15.c
index ea35453..7224c63 100644
--- a/babl/base/type-u15.c
+++ b/babl/base/type-u15.c
@@ -198,7 +198,7 @@ convert_u15_float_scaled (BablConversion *conversion,
MAKE_CONVERSIONS_float (u15, 0.0, 1.0, 0, (1<<15))
void
-babl_base_type_u15 (void)
+BABL_SIMD_SUFFIX (babl_base_type_u15) (void)
{
babl_hmpf_on_name_lookups--;
babl_type_new (
diff --git a/babl/base/type-u16.c b/babl/base/type-u16.c
index c5a41dc..e7ab936 100644
--- a/babl/base/type-u16.c
+++ b/babl/base/type-u16.c
@@ -196,7 +196,7 @@ MAKE_CONVERSIONS_float (u16, 0.0, 1.0, 0, UINT16_MAX)
void
-babl_base_type_u16 (void)
+BABL_SIMD_SUFFIX (babl_base_type_u16) (void)
{
babl_type_new (
"u16",
diff --git a/babl/base/type-u32.c b/babl/base/type-u32.c
index 48b1506..7d07ff1 100644
--- a/babl/base/type-u32.c
+++ b/babl/base/type-u32.c
@@ -69,7 +69,7 @@ convert_u32_double_scaled (BablConversion *c,
{
while (n--)
{
- int u32val = *(uint32_t *) src;
+ uint32_t u32val = *(uint32_t *) src;
double dval;
if (u32val < min)
@@ -154,7 +154,7 @@ convert_u32_float_scaled (BablConversion *c,
{
while (n--)
{
- int u32val = *(uint32_t *) src;
+ uint32_t u32val = *(uint32_t *) src;
float dval;
if (u32val < min)
@@ -196,7 +196,7 @@ MAKE_CONVERSIONS_float(u32, 0.0, 1.0, 0, UINT32_MAX)
void
-babl_base_type_u32 (void)
+BABL_SIMD_SUFFIX (babl_base_type_u32) (void)
{
babl_type_new (
"u32",
diff --git a/babl/base/type-u8.c b/babl/base/type-u8.c
index d41d5e0..9abbf67 100644
--- a/babl/base/type-u8.c
+++ b/babl/base/type-u8.c
@@ -202,7 +202,7 @@ MAKE_CONVERSIONS_float (u8_chroma, -0.5, 0.5, 16, 240)
void
-babl_base_type_u8 (void)
+BABL_SIMD_SUFFIX (babl_base_type_u8) (void)
{
babl_type_new (
"u8",
diff --git a/babl/base/util.h b/babl/base/util.h
index aba9c61..0d50363 100644
--- a/babl/base/util.h
+++ b/babl/base/util.h
@@ -50,23 +50,17 @@
static inline double
babl_epsilon_for_zero (double value)
{
- if (value <= BABL_ALPHA_FLOOR &&
- value >= -BABL_ALPHA_FLOOR)
- {
- return BABL_ALPHA_FLOOR;
- }
- return value;
+ return value * (value > BABL_ALPHA_FLOOR || value < -BABL_ALPHA_FLOOR) +
+ BABL_ALPHA_FLOOR * (value <= BABL_ALPHA_FLOOR &&
+ value >= -BABL_ALPHA_FLOOR);
}
static inline float
babl_epsilon_for_zero_float (float value)
{
- if (value <= BABL_ALPHA_FLOOR_F &&
- value >= -BABL_ALPHA_FLOOR_F)
- {
- return BABL_ALPHA_FLOOR_F;
- }
- return value;
+ return value * (value > BABL_ALPHA_FLOOR_F || value < -BABL_ALPHA_FLOOR_F) +
+ BABL_ALPHA_FLOOR_F * (value <= BABL_ALPHA_FLOOR_F &&
+ value >= -BABL_ALPHA_FLOOR_F);
}
diff --git a/babl/git-version.h b/babl/git-version.h
deleted file mode 100644
index 5f243e8..0000000
--- a/babl/git-version.h
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __GIT_VERSION_H__
-#define __GIT_VERSION_H__
-
-#define BABL_GIT_VERSION "BABL_0_1_80"
-
-#endif /* __GIT_VERSION_H__ */
diff --git a/babl/git-version.h.in b/babl/git-version.h.in
deleted file mode 100644
index a9f87e2..0000000
--- a/babl/git-version.h.in
+++ /dev/null
@@ -1,6 +0,0 @@
-#ifndef __GIT_VERSION_H__
-#define __GIT_VERSION_H__
-
-#define BABL_GIT_VERSION "@BABL_GIT_VERSION@"
-
-#endif /* __GIT_VERSION_H__ */
diff --git a/babl/meson.build b/babl/meson.build
index fed8fe9..6e7c57f 100644
--- a/babl/meson.build
+++ b/babl/meson.build
@@ -13,10 +13,10 @@ babl_c_args = [
# symbol maps
version_script = custom_target('babl.map',
- input : meson.source_root() / 'export-symbols',
+ input : export_symbols_file,
output: ['babl.map', 'babl.map.clang'],
command: [
- find_program(meson.source_root() / 'gen_babl_map.py'),
+ find_program(gen_babl_map_file),
'@INPUT@',
'@OUTPUT0@',
],
@@ -54,43 +54,14 @@ if platform_win32
babl_link_args += no_undefined
endif
+# sources
babl_version_h = configure_file(
input: 'babl-version.h.in',
output: 'babl-version.h',
configuration: conf,
)
-# If git is available, always check if git-version.h should be
-# updated. If git is not available, don't do anything if git-version.h
-# already exists because then we are probably working with a tarball
-# in which case the git-version.h we ship is correct.
-if git_bin.found() and run_command(
- git_bin,
- 'rev-parse',
- '--is-inside-work-tree',
-).returncode() == 0
- git_version_h = vcs_tag(
- input : 'git-version.h.in',
- output: 'git-version.h',
- replace_string: '@BABL_GIT_VERSION@',
- command: [ git_bin.path(), 'describe', '--always' ],
- )
-
- if env_bin.found()
- meson.add_dist_script(
- [ 'ninja', 'babl/git-version.h', ],
- )
- meson.add_dist_script(
- [ 'sh', '-c', ' '.join(
- [ 'cp', git_version_h.full_path(), '${MESON_DIST_ROOT}/babl' ]
- )]
- )
- endif
-else
- git_version_h = files('git-version.h')
-endif
-
-babl_sources = [
+babl_sources = files(
'babl-cache.c',
'babl-component.c',
'babl-conversion.c',
@@ -118,36 +89,56 @@ babl_sources = [
'babl-sampling.c',
'babl-sanity.c',
'babl-space.c',
- 'babl-trc.c',
'babl-type.c',
'babl-util.c',
'babl-version.c',
'babl.c',
+) + [
babl_version_h,
git_version_h,
]
-babl_headers = [
+babl_headers = files(
'babl-introspect.h',
'babl-macros.h',
'babl-types.h',
'babl.h',
+) + [
babl_version_h,
]
install_headers(babl_headers,
- subdir: join_paths(lib_name, 'babl')
+ subdir: lib_name / 'babl'
)
+# copy external headers to babl subdirectory for subproject builds as
+# we don't want to expose the project root folder due to potential
+# name clashes.
+if meson.is_subproject()
+ subdir('babl')
+endif
+babl_deps = [math, thread, dl, lcms]
+babl_includes = [rootInclude, bablBaseInclude]
+
+if host_cpu_family == 'x86_64'
+ simd_extra = [babl_base_x86_64_v2, babl_base_x86_64_v3]
+elif host_cpu_family == 'arm'
+ simd_extra = [babl_base_arm_neon]
+else
+ simd_extra = []
+endif
+
+# build library
babl = library(
lib_name,
babl_sources,
- include_directories: [rootInclude, bablBaseInclude],
+ include_directories: babl_includes,
c_args: babl_c_args,
link_whole: babl_base,
link_args: babl_link_args,
- dependencies: [math, thread, dl, lcms],
- link_depends: version_script,
+ link_with: simd_extra,
+ dependencies: babl_deps,
+ link_depends: version_script[0],
version: so_version,
install: true,
)
@@ -165,13 +156,16 @@ if build_gir
namespace: 'Babl',
nsversion: api_version,
header: 'babl.h',
+ export_packages: 'babl-0.1',
install: true,
)
if build_vapi
- gnome.generate_vapi(lib_name,
+ babl_vapi = gnome.generate_vapi(lib_name,
sources: babl_gir[0],
install: true,
)
endif
+else
+ babl_gir = []
endif