diff options
Diffstat (limited to 'babl')
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 |