void dt_configure_defaults() { const int atom_cores = dt_get_num_atom_cores(); const int threads = dt_get_num_threads(); const size_t mem = dt_get_total_memory(); const int bits = (sizeof(void*) == 4) ? 32 : 64; fprintf(stderr, "[defaults] found a %d-bit system with %zu kb ram and %d cores (%d atom based)\n", bits, mem, threads, atom_cores); if(mem > (2u<<20) && threads > 4) { fprintf(stderr, "[defaults] setting high quality defaults\n"); dt_conf_set_int("worker_threads", 8); dt_conf_set_int64("cache_memory", 1u<<30); dt_conf_set_int("plugins/lighttable/thumbnail_width", 1300); dt_conf_set_int("plugins/lighttable/thumbnail_height", 1000); dt_conf_set_bool("plugins/lighttable/low_quality_thumbnails", FALSE); } if(mem < (1u<<20) || threads <= 2 || bits < 64 || atom_cores > 0) { fprintf(stderr, "[defaults] setting very conservative defaults\n"); dt_conf_set_int("worker_threads", 1); dt_conf_set_int64("cache_memory", 200u<<20); dt_conf_set_int("host_memory_limit", 500); dt_conf_set_int("singlebuffer_limit", 8); dt_conf_set_int("plugins/lighttable/thumbnail_width", 800); dt_conf_set_int("plugins/lighttable/thumbnail_height", 500); dt_conf_set_string("plugins/darkroom/demosaic/quality", "always bilinear (fast)"); dt_conf_set_bool("plugins/lighttable/low_quality_thumbnails", TRUE); } }
void dt_configure_defaults() { const int atom_cores = dt_get_num_atom_cores(); const int threads = dt_get_num_threads(); const size_t mem = dt_get_total_memory(); const int bits = (sizeof(void *) == 4) ? 32 : 64; fprintf(stderr, "[defaults] found a %d-bit system with %zu kb ram and %d cores (%d atom based)\n", bits, mem, threads, atom_cores); if(mem >= (8u << 20) && threads > 4) { fprintf(stderr, "[defaults] setting very high quality defaults\n"); dt_conf_set_int("worker_threads", 8); // if no less than 8Gb, half the total size dt_conf_set_int("host_memory_limit", mem >> 11); dt_conf_set_bool("plugins/lighttable/low_quality_thumbnails", FALSE); }
void commit_params (struct dt_iop_module_t *self, dt_iop_params_t *p1, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece) { dt_iop_colorout_params_t *p = (dt_iop_colorout_params_t *)p1; dt_iop_colorout_data_t *d = (dt_iop_colorout_data_t *)piece->data; gchar *overprofile = dt_conf_get_string("plugins/lighttable/export/iccprofile"); const int overintent = dt_conf_get_int("plugins/lighttable/export/iccintent"); const int high_quality_processing = dt_conf_get_bool("plugins/lighttable/export/force_lcms2"); gchar *outprofile=NULL; int outintent = 0; /* cleanup profiles */ if (d->output) dt_colorspaces_cleanup_profile(d->output); d->output = NULL; if (d->softproof_enabled) dt_colorspaces_cleanup_profile(d->softproof); d->softproof = NULL; d->softproof_enabled = p->softproof_enabled; if(self->dev->gui_attached && self->gui_data != NULL) { dt_iop_colorout_gui_data_t *g = (dt_iop_colorout_gui_data_t *)self->gui_data; g->softproof_enabled = p->softproof_enabled; } const int num_threads = dt_get_num_threads(); if (d->xform) { cmsDeleteTransform(d->xform); d->xform = 0; } d->cmatrix[0] = NAN; d->lut[0][0] = -1.0f; d->lut[1][0] = -1.0f; d->lut[2][0] = -1.0f; piece->process_cl_ready = 1; /* if we are exporting then check and set usage of override profile */ if (pipe->type == DT_DEV_PIXELPIPE_EXPORT) { if (overprofile && strcmp(overprofile, "image")) snprintf(p->iccprofile, DT_IOP_COLOR_ICC_LEN, "%s", overprofile); if (overintent >= 0) p->intent = overintent; outprofile = p->iccprofile; outintent = p->intent; } else { /* we are not exporting, using display profile as output */ outprofile = p->displayprofile; outintent = p->displayintent; } /* creating output profile */ d->output = _create_profile(outprofile); /* creating softproof profile if softproof is enabled */ if (d->softproof_enabled) d->softproof = _create_profile(p->softproofprofile); /* * Setup transform flags */ uint32_t transformFlags = 0; /* TODO: the use of bpc should be userconfigurable either from module or preference pane */ /* softproof flag and black point compensation */ transformFlags |= (d->softproof_enabled ? cmsFLAGS_SOFTPROOFING|cmsFLAGS_NOCACHE|cmsFLAGS_BLACKPOINTCOMPENSATION : 0); /* get matrix from profile, if softproofing or high quality exporting always go xform codepath */ if (d->softproof_enabled || (pipe->type == DT_DEV_PIXELPIPE_EXPORT && high_quality_processing) || dt_colorspaces_get_matrix_from_output_profile (d->output, d->cmatrix, d->lut[0], d->lut[1], d->lut[2], LUT_SAMPLES)) { d->cmatrix[0] = NAN; piece->process_cl_ready = 0; d->xform = cmsCreateProofingTransform(d->Lab, TYPE_Lab_FLT, d->output, TYPE_RGB_FLT, d->softproof, outintent, INTENT_RELATIVE_COLORIMETRIC, transformFlags); } // user selected a non-supported output profile, check that: if (!d->xform && isnan(d->cmatrix[0])) { dt_control_log(_("unsupported output profile has been replaced by sRGB!")); if (d->output) dt_colorspaces_cleanup_profile(d->output); d->output = dt_colorspaces_create_srgb_profile(); if (d->softproof_enabled || dt_colorspaces_get_matrix_from_output_profile (d->output, d->cmatrix, d->lut[0], d->lut[1], d->lut[2], LUT_SAMPLES)) { d->cmatrix[0] = NAN; piece->process_cl_ready = 0; for (int t=0; t<num_threads; t++) d->xform = cmsCreateProofingTransform(d->Lab, TYPE_Lab_FLT, d->output, TYPE_RGB_FLT, d->softproof, outintent, INTENT_RELATIVE_COLORIMETRIC, transformFlags); } } // now try to initialize unbounded mode: // we do extrapolation for input values above 1.0f. // unfortunately we can only do this if we got the computation // in our hands, i.e. for the fast builtin-dt-matrix-profile path. for(int k=0;k<3;k++) { // omit luts marked as linear (negative as marker) if(d->lut[k][0] >= 0.0f) { const float x[4] = {0.7f, 0.8f, 0.9f, 1.0f}; const float y[4] = {lerp_lut(d->lut[k], x[0]), lerp_lut(d->lut[k], x[1]), lerp_lut(d->lut[k], x[2]), lerp_lut(d->lut[k], x[3])}; dt_iop_estimate_exp(x, y, 4, d->unbounded_coeffs[k]); } else d->unbounded_coeffs[k][0] = -1.0f; } //fprintf(stderr, " Output profile %s, softproof %s%s%s\n", outprofile, d->softproofing?"enabled ":"disabled",d->softproofing?"using profile ":"",d->softproofing?g->softproofprofile:""); g_free(overprofile); }
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { dt_iop_bloom_data_t *data = (dt_iop_bloom_data_t *)piece->data; float *in = (float *)ivoid; float *out = (float *)ovoid; const int ch = piece->colors; /* gather light by threshold */ float *blurlightness = calloc((size_t)roi_out->width * roi_out->height, sizeof(float)); memcpy(out, in, (size_t)roi_out->width * roi_out->height * ch * sizeof(float)); const int rad = 256.0f * (fmin(100.0f, data->size + 1.0f) / 100.0f); const float _r = ceilf(rad * roi_in->scale / piece->iscale); const int radius = MIN(256.0f, _r); const float scale = 1.0f / exp2f(-1.0f * (fmin(100.0f, data->strength + 1.0f) / 100.0f)); /* get the thresholded lights into buffer */ #ifdef _OPENMP #pragma omp parallel for default(none) shared(data, blurlightness) schedule(static) #endif for(size_t k = 0; k < (size_t)roi_out->width * roi_out->height; k++) { float *inp = ((float *)ivoid) + ch * k; const float L = inp[0] * scale; if(L > data->threshold) blurlightness[k] = L; } /* horizontal blur into memchannel lightness */ const int range = 2 * radius + 1; const int hr = range / 2; const size_t size = roi_out->width > roi_out->height ? roi_out->width : roi_out->height; float *const scanline_buf = malloc(size * dt_get_num_threads() * sizeof(float)); for(int iteration = 0; iteration < BOX_ITERATIONS; iteration++) { #ifdef _OPENMP #pragma omp parallel for default(none) shared(blurlightness) schedule(static) #endif for(int y = 0; y < roi_out->height; y++) { float *scanline = scanline_buf + size * dt_get_thread_num(); float L = 0; int hits = 0; const size_t index = (size_t)y * roi_out->width; for(int x = -hr; x < roi_out->width; x++) { int op = x - hr - 1; int np = x + hr; if(op >= 0) { L -= blurlightness[index + op]; hits--; } if(np < roi_out->width) { L += blurlightness[index + np]; hits++; } if(x >= 0) scanline[x] = L / hits; } for(int x = 0; x < roi_out->width; x++) blurlightness[index + x] = scanline[x]; } /* vertical pass on blurlightness */ const int opoffs = -(hr + 1) * roi_out->width; const int npoffs = (hr)*roi_out->width; #ifdef _OPENMP #pragma omp parallel for default(none) shared(blurlightness) schedule(static) #endif for(int x = 0; x < roi_out->width; x++) { float *scanline = scanline_buf + size * dt_get_thread_num(); float L = 0; int hits = 0; size_t index = (size_t)x - hr * roi_out->width; for(int y = -hr; y < roi_out->height; y++) { int op = y - hr - 1; int np = y + hr; if(op >= 0) { L -= blurlightness[index + opoffs]; hits--; } if(np < roi_out->height) { L += blurlightness[index + npoffs]; hits++; } if(y >= 0) scanline[y] = L / hits; index += roi_out->width; } for(int y = 0; y < roi_out->height; y++) blurlightness[y * roi_out->width + x] = scanline[y]; } } free(scanline_buf); /* screen blend lightness with original */ #ifdef _OPENMP #pragma omp parallel for default(none) shared(in, out, data, blurlightness) schedule(static) #endif for(size_t k = 0; k < (size_t)roi_out->width * roi_out->height; k++) { float *inp = in + ch * k; float *outp = out + ch * k; outp[0] = 100.0f - (((100.0f - inp[0]) * (100.0f - blurlightness[k])) / 100.0f); // Screen blend outp[1] = inp[1]; outp[2] = inp[2]; } if(piece->pipe->mask_display) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height); free(blurlightness); }
int dt_init(int argc, char *argv[], const int init_gui,lua_State *L) { #ifndef __WIN32__ if(getuid() == 0 || geteuid() == 0) printf("WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n"); #endif // make everything go a lot faster. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #if !defined __APPLE__ && !defined __WIN32__ _dt_sigsegv_old_handler = signal(SIGSEGV,&_dt_sigsegv_handler); #endif #ifndef __GNUC_PREREQ // on OSX, gcc-4.6 and clang chokes if this is not here. #if defined __GNUC__ && defined __GNUC_MINOR__ # define __GNUC_PREREQ(maj, min) \ ((__GNUC__ << 16) + __GNUC_MINOR__ >= ((maj) << 16) + (min)) #else # define __GNUC_PREREQ(maj, min) 0 #endif #endif #ifndef __has_builtin // http://clang.llvm.org/docs/LanguageExtensions.html#feature-checking-macros #define __has_builtin(x) false #endif #ifndef __SSE3__ #error "Unfortunately we depend on SSE3 instructions at this time." #error "Please contribute a backport patch (or buy a newer processor)." #else #if (__GNUC_PREREQ(4,8) || __has_builtin(__builtin_cpu_supports)) //FIXME: check will work only in GCC 4.8+ !!! implement manual cpuid check !!! //NOTE: _may_i_use_cpu_feature() looks better, but only avaliable in ICC if (!__builtin_cpu_supports("sse3")) { fprintf(stderr, "[dt_init] unfortunately we depend on SSE3 instructions at this time.\n"); fprintf(stderr, "[dt_init] please contribute a backport patch (or buy a newer processor).\n"); return 1; } #else //FIXME: no way to check for SSE3 in runtime, implement manual cpuid check !!! #endif #endif #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD,128*1024) ; /* use mmap() for large allocations */ #endif // we have to have our share dir in XDG_DATA_DIRS, // otherwise GTK+ won't find our logo for the about screen (and maybe other things) { const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS"); gchar *new_xdg_data_dirs = NULL; gboolean set_env = TRUE; if(xdg_data_dirs != NULL && *xdg_data_dirs != '\0') { // check if DARKTABLE_SHAREDIR is already in there gboolean found = FALSE; gchar **tokens = g_strsplit(xdg_data_dirs, ":", 0); // xdg_data_dirs is neither NULL nor empty => tokens != NULL for(char **iter = tokens; *iter != NULL; iter++) if(!strcmp(DARKTABLE_SHAREDIR, *iter)) { found = TRUE; break; } g_strfreev(tokens); if(found) set_env = FALSE; else new_xdg_data_dirs = g_strjoin(":", DARKTABLE_SHAREDIR, xdg_data_dirs, NULL); } else { // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a default if(!g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share/") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share/")) new_xdg_data_dirs = g_strdup("/usr/local/share/:/usr/share/"); else new_xdg_data_dirs = g_strdup_printf("%s:/usr/local/share/:/usr/share/", DARKTABLE_SHAREDIR); } if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1); g_free(new_xdg_data_dirs); } setlocale(LC_ALL, ""); bindtextdomain (GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); // init all pointers to 0: memset(&darktable, 0, sizeof(darktable_t)); darktable.progname = argv[0]; // database gchar *dbfilename_from_command = NULL; char *datadir_from_command = NULL; char *moduledir_from_command = NULL; char *tmpdir_from_command = NULL; char *configdir_from_command = NULL; char *cachedir_from_command = NULL; #ifdef USE_LUA char *lua_command = NULL; #endif darktable.num_openmp_threads = 1; #ifdef _OPENMP darktable.num_openmp_threads = omp_get_num_procs(); #endif darktable.unmuted = 0; GSList *images_to_load = NULL, *config_override = NULL; for(int k=1; k<argc; k++) { if(argv[k][0] == '-') { if(!strcmp(argv[k], "--help")) { return usage(argv[0]); } if(!strcmp(argv[k], "-h")) { return usage(argv[0]); } else if(!strcmp(argv[k], "--version")) { printf("this is "PACKAGE_STRING"\ncopyright (c) 2009-2014 johannes hanika\n"PACKAGE_BUGREPORT"\n" #ifdef _OPENMP "OpenMP support enabled\n" #else "OpenMP support disabled\n" #endif ); return 1; } else if(!strcmp(argv[k], "--library")) { dbfilename_from_command = argv[++k]; } else if(!strcmp(argv[k], "--datadir")) { datadir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--moduledir")) { moduledir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--tmpdir")) { tmpdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--configdir")) { configdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--cachedir")) { cachedir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--localedir")) { bindtextdomain (GETTEXT_PACKAGE, argv[++k]); } else if(argv[k][1] == 'd' && argc > k+1) { if(!strcmp(argv[k+1], "all")) darktable.unmuted = 0xffffffff; // enable all debug information else if(!strcmp(argv[k+1], "cache")) darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module else if(!strcmp(argv[k+1], "control")) darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module else if(!strcmp(argv[k+1], "dev")) darktable.unmuted |= DT_DEBUG_DEV; // develop module else if(!strcmp(argv[k+1], "fswatch")) darktable.unmuted |= DT_DEBUG_FSWATCH; // fswatch module else if(!strcmp(argv[k+1], "input")) darktable.unmuted |= DT_DEBUG_INPUT; // input devices else if(!strcmp(argv[k+1], "camctl")) darktable.unmuted |= DT_DEBUG_CAMCTL; // camera control module else if(!strcmp(argv[k+1], "perf")) darktable.unmuted |= DT_DEBUG_PERF; // performance measurements else if(!strcmp(argv[k+1], "pwstorage")) darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module else if(!strcmp(argv[k+1], "opencl")) darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl else if(!strcmp(argv[k+1], "sql")) darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries else if(!strcmp(argv[k+1], "memory")) darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then. else if(!strcmp(argv[k+1], "lighttable")) darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff. else if(!strcmp(argv[k+1], "nan")) darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe. else if(!strcmp(argv[k+1], "masks")) darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff. else if(!strcmp(argv[k+1], "lua")) darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console else return usage(argv[0]); k ++; } else if(argv[k][1] == 't' && argc > k+1) { darktable.num_openmp_threads = CLAMP(atol(argv[k+1]), 1, 100); printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads); k ++; } else if(!strcmp(argv[k], "--conf")) { gchar *keyval = g_strdup(argv[++k]), *c = keyval; gchar *end = keyval + strlen(keyval); while(*c != '=' && c < end) c++; if(*c == '=' && *(c+1) != '\0') { *c++ = '\0'; dt_conf_string_entry_t *entry = (dt_conf_string_entry_t*)g_malloc(sizeof(dt_conf_string_entry_t)); entry->key = g_strdup(keyval); entry->value = g_strdup(c); config_override = g_slist_append(config_override, entry); } g_free(keyval); } else if(!strcmp(argv[k], "--luacmd")) { #ifdef USE_LUA lua_command = argv[++k]; #else ++k; #endif } } #ifndef MAC_INTEGRATION else { images_to_load = g_slist_append(images_to_load, argv[k]); } #endif } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] at startup\n"); dt_print_mem_usage(); } #ifdef _OPENMP omp_set_num_threads(darktable.num_openmp_threads); #endif dt_loc_init_datadir(datadir_from_command); dt_loc_init_plugindir(moduledir_from_command); if(dt_loc_init_tmp_dir(tmpdir_from_command)) { printf(_("ERROR : invalid temporary directory : %s\n"),darktable.tmpdir); return usage(argv[0]); } dt_loc_init_user_config_dir(configdir_from_command); dt_loc_init_user_cache_dir(cachedir_from_command); #if !GLIB_CHECK_VERSION(2, 35, 0) g_type_init(); #endif // does not work, as gtk is not inited yet. // even if it were, it's a super bad idea to invoke gtk stuff from // a signal handler. /* check cput caps */ // dt_check_cpu(argc,argv); #ifdef HAVE_GEGL char geglpath[PATH_MAX]; char datadir[PATH_MAX]; dt_loc_get_datadir(datadir, sizeof(datadir)); snprintf(geglpath, sizeof(geglpath), "%s/gegl:/usr/lib/gegl-0.0", datadir); (void)setenv("GEGL_PATH", geglpath, 1); gegl_init(&argc, &argv); #endif #ifdef USE_LUA dt_lua_init_early(L); #endif // thread-safe init: dt_exif_init(); char datadir[PATH_MAX]; dt_loc_get_user_config_dir (datadir, sizeof(datadir)); char filename[PATH_MAX]; snprintf(filename, sizeof(filename), "%s/darktablerc", datadir); // initialize the config backend. this needs to be done first... darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t)); dt_conf_init(darktable.conf, filename, config_override); g_slist_free_full(config_override, g_free); // set the interface language const gchar* lang = dt_conf_get_string("ui_last/gui_language"); // we may not g_free 'lang' since it is owned by setlocale afterwards if(lang != NULL && lang[0] != '\0') { if(setlocale(LC_ALL, lang) != NULL) gtk_disable_setlocale(); } // initialize the database darktable.db = dt_database_init(dbfilename_from_command); if(darktable.db == NULL) { printf("ERROR : cannot open database\n"); return 1; } else if(!dt_database_get_lock_acquired(darktable.db)) { // send the images to the other instance via dbus if(images_to_load) { GSList *p = images_to_load; // get a connection! GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SESSION,NULL, NULL); while (p != NULL) { // make the filename absolute ... gchar *filename = dt_make_path_absolute((gchar*)p->data); if(filename == NULL) continue; // ... and send it to the running instance of darktable g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable", "org.darktable.service.Remote", "Open", g_variant_new ("(s)", filename), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); p = g_slist_next(p); g_free(filename); } g_slist_free(images_to_load); g_object_unref(connection); } return 1; } // Initialize the signal system darktable.signals = dt_control_signal_init(); // Make sure that the database and xmp files are in sync before starting the fswatch. // We need conf and db to be up and running for that which is the case here. // FIXME: is this also useful in non-gui mode? GList *changed_xmp_files = NULL; if(init_gui && dt_conf_get_bool("run_crawler_on_start")) { changed_xmp_files = dt_control_crawler_run(); } // Initialize the filesystem watcher darktable.fswatch=dt_fswatch_new(); #ifdef HAVE_GPHOTO2 // Initialize the camera control darktable.camctl=dt_camctl_new(); #endif // get max lighttable thumbnail size: darktable.thumbnail_width = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_width"), 200, 3000); darktable.thumbnail_height = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_height"), 200, 3000); // and make sure it can be mip-mapped all the way from mip4 to mip0 darktable.thumbnail_width /= 16; darktable.thumbnail_width *= 16; darktable.thumbnail_height /= 16; darktable.thumbnail_height *= 16; // Initialize the password storage engine darktable.pwstorage=dt_pwstorage_new(); // FIXME: move there into dt_database_t dt_pthread_mutex_init(&(darktable.db_insert), NULL); dt_pthread_mutex_init(&(darktable.plugin_threadsafe), NULL); dt_pthread_mutex_init(&(darktable.capabilities_threadsafe), NULL); darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t)); if(init_gui) { dt_control_init(darktable.control); } else { if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:")) dt_gui_presets_init(); // init preset db schema. darktable.control->running = 0; darktable.control->accelerators = NULL; dt_pthread_mutex_init(&darktable.control->run_mutex, NULL); } // initialize collection query darktable.collection_listeners = NULL; darktable.collection = dt_collection_new(NULL); /* initialize selection */ darktable.selection = dt_selection_new(); /* capabilities set to NULL */ darktable.capabilities = NULL; #ifdef HAVE_GRAPHICSMAGICK /* GraphicsMagick init */ InitializeMagick(darktable.progname); #endif darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t)); #ifdef HAVE_OPENCL dt_opencl_init(darktable.opencl, argc, argv); #endif darktable.blendop = (dt_blendop_t *)calloc(1, sizeof(dt_blendop_t)); dt_develop_blend_init(darktable.blendop); darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t)); dt_points_init(darktable.points, dt_get_num_threads()); // must come before mipmap_cache, because that one will need to access // image dimensions stored in here: darktable.image_cache = (dt_image_cache_t *)calloc(1, sizeof(dt_image_cache_t)); dt_image_cache_init(darktable.image_cache); darktable.mipmap_cache = (dt_mipmap_cache_t *)calloc(1, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); // The GUI must be initialized before the views, because the init() // functions of the views depend on darktable.control->accels_* to register // their keyboard accelerators if(init_gui) { darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t)); if(dt_gui_gtk_init(darktable.gui, argc, argv)) return 1; dt_bauhaus_init(); } else darktable.gui = NULL; darktable.view_manager = (dt_view_manager_t *)calloc(1, sizeof(dt_view_manager_t)); dt_view_manager_init(darktable.view_manager); darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); // load the darkroom mode plugins once: dt_iop_load_modules_so(); if(init_gui) { darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t)); dt_lib_init(darktable.lib); dt_control_load_config(darktable.control); } if(init_gui) { // Loading the keybindings char keyfile[PATH_MAX]; // First dump the default keymapping snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc_default", datadir); gtk_accel_map_save(keyfile); // Removing extraneous semi-colons from the default keymap strip_semicolons_from_keymap(keyfile); // Then load any modified keys if available snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc", datadir); if(g_file_test(keyfile, G_FILE_TEST_EXISTS)) gtk_accel_map_load(keyfile); else gtk_accel_map_save(keyfile); // Save the default keymap if none is present // I doubt that connecting to dbus for darktable-cli makes sense darktable.dbus = dt_dbus_init(); // initialize undo struct darktable.undo = dt_undo_init(); // load image(s) specified on cmdline int id = 0; if(images_to_load) { // If only one image is listed, attempt to load it in darkroom gboolean load_in_dr = (g_slist_next(images_to_load) == NULL); GSList *p = images_to_load; while (p != NULL) { // don't put these function calls into MAX(), the macro will evaluate // it twice (and happily deadlock, in this particular case) int newid = dt_load_from_string((gchar*)p->data, load_in_dr); id = MAX(id, newid); p = g_slist_next(p); } if (!load_in_dr || id == 0) dt_ctl_switch_mode_to(DT_LIBRARY); g_slist_free(images_to_load); } else dt_ctl_switch_mode_to(DT_LIBRARY); } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] after successful startup\n"); dt_print_mem_usage(); } dt_image_local_copy_synch(); /* init lua last, since it's user made stuff it must be in the real environment */ #ifdef USE_LUA dt_lua_init(darktable.lua_state.state,lua_command); #endif // last but not least construct the popup that asks the user about images whose xmp files are newer than the db entry if(init_gui && changed_xmp_files) { dt_control_crawler_show_image_list(changed_xmp_files); } return 0; }
void process(struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out) { dt_iop_rlce_data_t *data = (dt_iop_rlce_data_t *)piece->data; const int ch = piece->colors; // PASS1: Get a luminance map of image... float *luminance = (float *)malloc(((size_t)roi_out->width * roi_out->height) * sizeof(float)); // double lsmax=0.0,lsmin=1.0; #ifdef _OPENMP #pragma omp parallel for default(none) schedule(static) shared(luminance) #endif for(int j = 0; j < roi_out->height; j++) { float *in = (float *)ivoid + (size_t)j * roi_out->width * ch; float *lm = luminance + (size_t)j * roi_out->width; for(int i = 0; i < roi_out->width; i++) { double pmax = CLIP(fmax(in[0], fmax(in[1], in[2]))); // Max value in RGB set double pmin = CLIP(fmin(in[0], fmin(in[1], in[2]))); // Min value in RGB set *lm = (pmax + pmin) / 2.0; // Pixel luminocity in += ch; lm++; } } // Params const int rad = data->radius * roi_in->scale / piece->iscale; #define BINS (256) const float slope = data->slope; const size_t destbuf_size = roi_out->width; float *const dest_buf = malloc(destbuf_size * sizeof(float) * dt_get_num_threads()); // CLAHE #ifdef _OPENMP #pragma omp parallel for default(none) schedule(static) shared(luminance) #endif for(int j = 0; j < roi_out->height; j++) { int yMin = fmax(0, j - rad); int yMax = fmin(roi_in->height, j + rad + 1); int h = yMax - yMin; int xMin0 = fmax(0, 0 - rad); int xMax0 = fmin(roi_in->width - 1, rad); int hist[BINS + 1]; int clippedhist[BINS + 1]; float *dest = dest_buf + destbuf_size * dt_get_thread_num(); /* initially fill histogram */ memset(hist, 0, (BINS + 1) * sizeof(int)); for(int yi = yMin; yi < yMax; ++yi) for(int xi = xMin0; xi < xMax0; ++xi) ++hist[ROUND_POSISTIVE(luminance[(size_t)yi * roi_in->width + xi] * (float)BINS)]; // Destination row memset(dest, 0, roi_out->width * sizeof(float)); float *ld = dest; for(int i = 0; i < roi_out->width; i++) { int v = ROUND_POSISTIVE(luminance[(size_t)j * roi_in->width + i] * (float)BINS); int xMin = fmax(0, i - rad); int xMax = i + rad + 1; int w = fmin(roi_in->width, xMax) - xMin; int n = h * w; int limit = (int)(slope * n / BINS + 0.5f); /* remove left behind values from histogram */ if(xMin > 0) { int xMin1 = xMin - 1; for(int yi = yMin; yi < yMax; ++yi) --hist[ROUND_POSISTIVE(luminance[(size_t)yi * roi_in->width + xMin1] * (float)BINS)]; } /* add newly included values to histogram */ if(xMax <= roi_in->width) { int xMax1 = xMax - 1; for(int yi = yMin; yi < yMax; ++yi) ++hist[ROUND_POSISTIVE(luminance[(size_t)yi * roi_in->width + xMax1] * (float)BINS)]; } /* clip histogram and redistribute clipped entries */ memcpy(clippedhist, hist, (BINS + 1) * sizeof(int)); int ce = 0, ceb = 0; do { ceb = ce; ce = 0; for(int b = 0; b <= BINS; b++) { int d = clippedhist[b] - limit; if(d > 0) { ce += d; clippedhist[b] = limit; } } int d = (ce / (float)(BINS + 1)); int m = ce % (BINS + 1); for(int b = 0; b <= BINS; b++) clippedhist[b] += d; if(m != 0) { int s = BINS / (float)m; for(int b = 0; b <= BINS; b += s) ++clippedhist[b]; } } while(ce != ceb); /* build cdf of clipped histogram */ int hMin = BINS; for(int b = 0; b < hMin; b++) if(clippedhist[b] != 0) hMin = b; int cdf = 0; for(int b = hMin; b <= v; b++) cdf += clippedhist[b]; int cdfMax = cdf; for(int b = v + 1; b <= BINS; b++) cdfMax += clippedhist[b]; int cdfMin = clippedhist[hMin]; *ld = (cdf - cdfMin) / (float)(cdfMax - cdfMin); ld++; } // Apply row float *in = ((float *)ivoid) + (size_t)j * roi_out->width * ch; float *out = ((float *)ovoid) + (size_t)j * roi_out->width * ch; for(int r = 0; r < roi_out->width; r++) { float H, S, L; rgb2hsl(in, &H, &S, &L); // hsl2rgb(out,H,S,( L / dest[r] ) * (L-lsmin) + lsmin ); hsl2rgb(out, H, S, dest[r]); out += ch; in += ch; ld++; } } free(dest_buf); // Cleanup free(luminance); #undef BINS }
int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load_data, lua_State *L) { double start_wtime = dt_get_wtime(); #ifndef __WIN32__ if(getuid() == 0 || geteuid() == 0) printf( "WARNING: either your user id or the effective user id are 0. are you running darktable as root?\n"); #endif #if defined(__SSE__) // make everything go a lot faster. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #endif dt_set_signal_handlers(); #include "is_supported_platform.h" int sse2_supported = 0; #ifdef HAVE_BUILTIN_CPU_SUPPORTS // NOTE: _may_i_use_cpu_feature() looks better, but only avaliable in ICC __builtin_cpu_init(); sse2_supported = __builtin_cpu_supports("sse2"); #else sse2_supported = dt_detect_cpu_features() & CPU_FLAG_SSE2; #endif if(!sse2_supported) { fprintf(stderr, "[dt_init] SSE2 instruction set is unavailable.\n"); fprintf(stderr, "[dt_init] expect a LOT of functionality to be broken. you have been warned.\n"); } #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD, 128 * 1024); /* use mmap() for large allocations */ #endif // make sure that stack/frame limits are good (musl) dt_set_rlimits(); // we have to have our share dir in XDG_DATA_DIRS, // otherwise GTK+ won't find our logo for the about screen (and maybe other things) { const gchar *xdg_data_dirs = g_getenv("XDG_DATA_DIRS"); gchar *new_xdg_data_dirs = NULL; gboolean set_env = TRUE; if(xdg_data_dirs != NULL && *xdg_data_dirs != '\0') { // check if DARKTABLE_SHAREDIR is already in there gboolean found = FALSE; gchar **tokens = g_strsplit(xdg_data_dirs, G_SEARCHPATH_SEPARATOR_S, 0); // xdg_data_dirs is neither NULL nor empty => tokens != NULL for(char **iter = tokens; *iter != NULL; iter++) if(!strcmp(DARKTABLE_SHAREDIR, *iter)) { found = TRUE; break; } g_strfreev(tokens); if(found) set_env = FALSE; else new_xdg_data_dirs = g_strjoin(G_SEARCHPATH_SEPARATOR_S, DARKTABLE_SHAREDIR, xdg_data_dirs, NULL); } else { #ifndef _WIN32 // see http://standards.freedesktop.org/basedir-spec/latest/ar01s03.html for a reason to use those as a // default if(!g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/local/share/") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share") || !g_strcmp0(DARKTABLE_SHAREDIR, "/usr/share/")) new_xdg_data_dirs = g_strdup("/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/"); else new_xdg_data_dirs = g_strdup_printf("%s" G_SEARCHPATH_SEPARATOR_S "/usr/local/share/" G_SEARCHPATH_SEPARATOR_S "/usr/share/", DARKTABLE_SHAREDIR); #else set_env = FALSE; #endif } if(set_env) g_setenv("XDG_DATA_DIRS", new_xdg_data_dirs, 1); g_free(new_xdg_data_dirs); } setlocale(LC_ALL, ""); bindtextdomain(GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR); bind_textdomain_codeset(GETTEXT_PACKAGE, "UTF-8"); textdomain(GETTEXT_PACKAGE); // init all pointers to 0: memset(&darktable, 0, sizeof(darktable_t)); darktable.start_wtime = start_wtime; darktable.progname = argv[0]; // FIXME: move there into dt_database_t dt_pthread_mutex_init(&(darktable.db_insert), NULL); dt_pthread_mutex_init(&(darktable.plugin_threadsafe), NULL); dt_pthread_mutex_init(&(darktable.capabilities_threadsafe), NULL); darktable.control = (dt_control_t *)calloc(1, sizeof(dt_control_t)); // database char *dbfilename_from_command = NULL; char *noiseprofiles_from_command = NULL; char *datadir_from_command = NULL; char *moduledir_from_command = NULL; char *tmpdir_from_command = NULL; char *configdir_from_command = NULL; char *cachedir_from_command = NULL; #ifdef HAVE_OPENCL gboolean exclude_opencl = FALSE; gboolean print_statistics = strcmp(argv[0], "darktable-cltest"); #endif #ifdef USE_LUA char *lua_command = NULL; #endif darktable.num_openmp_threads = 1; #ifdef _OPENMP darktable.num_openmp_threads = omp_get_num_procs(); #endif darktable.unmuted = 0; GSList *config_override = NULL; for(int k = 1; k < argc; k++) { if(argv[k][0] == '-') { if(!strcmp(argv[k], "--help")) { return usage(argv[0]); } if(!strcmp(argv[k], "-h")) { return usage(argv[0]); } else if(!strcmp(argv[k], "--version")) { #ifdef USE_LUA const char *lua_api_version = strcmp(LUA_API_VERSION_SUFFIX, "") ? STR(LUA_API_VERSION_MAJOR) "." STR(LUA_API_VERSION_MINOR) "." STR(LUA_API_VERSION_PATCH) "-" LUA_API_VERSION_SUFFIX : STR(LUA_API_VERSION_MAJOR) "." STR(LUA_API_VERSION_MINOR) "." STR(LUA_API_VERSION_PATCH); #endif printf("this is %s\ncopyright (c) 2009-%s johannes hanika\n" PACKAGE_BUGREPORT "\n\ncompile options:\n" " bit depth is %s\n" #ifdef _DEBUG " debug build\n" #else " normal build\n" #endif #if defined(__SSE2__) && defined(__SSE__) " SSE2 optimized codepath enabled\n" #else " SSE2 optimized codepath disabled\n" #endif #ifdef _OPENMP " OpenMP support enabled\n" #else " OpenMP support disabled\n" #endif #ifdef HAVE_OPENCL " OpenCL support enabled\n" #else " OpenCL support disabled\n" #endif #ifdef USE_LUA " Lua support enabled, API version %s\n" #else " Lua support disabled\n" #endif #ifdef USE_COLORDGTK " Colord support enabled\n" #else " Colord support disabled\n" #endif #ifdef HAVE_GPHOTO2 " gPhoto2 support enabled\n" #else " gPhoto2 support disabled\n" #endif #ifdef HAVE_GRAPHICSMAGICK " GraphicsMagick support enabled\n" #else " GraphicsMagick support disabled\n" #endif #ifdef HAVE_OPENEXR " OpenEXR support enabled\n" #else " OpenEXR support disabled\n" #endif , darktable_package_string, darktable_last_commit_year, (sizeof(void *) == 8 ? "64 bit" : sizeof(void *) == 4 ? "32 bit" : "unknown") #if USE_LUA , lua_api_version #endif ); return 1; } else if(!strcmp(argv[k], "--library") && argc > k + 1) { dbfilename_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--datadir") && argc > k + 1) { datadir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--moduledir") && argc > k + 1) { moduledir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--tmpdir") && argc > k + 1) { tmpdir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--configdir") && argc > k + 1) { configdir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--cachedir") && argc > k + 1) { cachedir_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--localedir") && argc > k + 1) { bindtextdomain(GETTEXT_PACKAGE, argv[++k]); argv[k-1] = NULL; argv[k] = NULL; } else if(argv[k][1] == 'd' && argc > k + 1) { if(!strcmp(argv[k + 1], "all")) darktable.unmuted = 0xffffffff; // enable all debug information else if(!strcmp(argv[k + 1], "cache")) darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module else if(!strcmp(argv[k + 1], "control")) darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module else if(!strcmp(argv[k + 1], "dev")) darktable.unmuted |= DT_DEBUG_DEV; // develop module else if(!strcmp(argv[k + 1], "input")) darktable.unmuted |= DT_DEBUG_INPUT; // input devices else if(!strcmp(argv[k + 1], "camctl")) darktable.unmuted |= DT_DEBUG_CAMCTL; // camera control module else if(!strcmp(argv[k + 1], "perf")) darktable.unmuted |= DT_DEBUG_PERF; // performance measurements else if(!strcmp(argv[k + 1], "pwstorage")) darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module else if(!strcmp(argv[k + 1], "opencl")) darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl else if(!strcmp(argv[k + 1], "sql")) darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries else if(!strcmp(argv[k + 1], "memory")) darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then. else if(!strcmp(argv[k + 1], "lighttable")) darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff. else if(!strcmp(argv[k + 1], "nan")) darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe. else if(!strcmp(argv[k + 1], "masks")) darktable.unmuted |= DT_DEBUG_MASKS; // masks related stuff. else if(!strcmp(argv[k + 1], "lua")) darktable.unmuted |= DT_DEBUG_LUA; // lua errors are reported on console else if(!strcmp(argv[k + 1], "print")) darktable.unmuted |= DT_DEBUG_PRINT; // print errors are reported on console else if(!strcmp(argv[k + 1], "camsupport")) darktable.unmuted |= DT_DEBUG_CAMERA_SUPPORT; // camera support warnings are reported on console else return usage(argv[0]); k++; argv[k-1] = NULL; argv[k] = NULL; } else if(argv[k][1] == 't' && argc > k + 1) { darktable.num_openmp_threads = CLAMP(atol(argv[k + 1]), 1, 100); printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads); k++; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--conf") && argc > k + 1) { gchar *keyval = g_strdup(argv[++k]), *c = keyval; argv[k-1] = NULL; argv[k] = NULL; gchar *end = keyval + strlen(keyval); while(*c != '=' && c < end) c++; if(*c == '=' && *(c + 1) != '\0') { *c++ = '\0'; dt_conf_string_entry_t *entry = (dt_conf_string_entry_t *)g_malloc(sizeof(dt_conf_string_entry_t)); entry->key = g_strdup(keyval); entry->value = g_strdup(c); config_override = g_slist_append(config_override, entry); } g_free(keyval); } else if(!strcmp(argv[k], "--noiseprofiles") && argc > k + 1) { noiseprofiles_from_command = argv[++k]; argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--luacmd") && argc > k + 1) { #ifdef USE_LUA lua_command = argv[++k]; #else ++k; #endif argv[k-1] = NULL; argv[k] = NULL; } else if(!strcmp(argv[k], "--disable-opencl")) { #ifdef HAVE_OPENCL exclude_opencl = TRUE; #endif argv[k] = NULL; } else if(!strcmp(argv[k], "--")) { // "--" confuses the argument parser of glib/gtk. remove it. argv[k] = NULL; break; } else return usage(argv[0]); // fail on unrecognized options } } // remove the NULLs to not confuse gtk_init() later. for(int i = 1; i < argc; i++) { int k; for(k = i; k < argc; k++) if(argv[k] != NULL) break; if(k > i) { k -= i; for(int j = i + k; j < argc; j++) { argv[j-k] = argv[j]; argv[j] = NULL; } argc -= k; } } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] at startup\n"); dt_print_mem_usage(); } if(init_gui) { // I doubt that connecting to dbus for darktable-cli makes sense darktable.dbus = dt_dbus_init(); // make sure that we have no stale global progress bar visible. thus it's run as early is possible dt_control_progress_init(darktable.control); } #ifdef _OPENMP omp_set_num_threads(darktable.num_openmp_threads); #endif dt_loc_init_datadir(datadir_from_command); dt_loc_init_plugindir(moduledir_from_command); if(dt_loc_init_tmp_dir(tmpdir_from_command)) { fprintf(stderr, "error: invalid temporary directory: %s\n", darktable.tmpdir); return usage(argv[0]); } dt_loc_init_user_config_dir(configdir_from_command); dt_loc_init_user_cache_dir(cachedir_from_command); #ifdef USE_LUA dt_lua_init_early(L); #endif // thread-safe init: dt_exif_init(); char datadir[PATH_MAX] = { 0 }; dt_loc_get_user_config_dir(datadir, sizeof(datadir)); char darktablerc[PATH_MAX] = { 0 }; snprintf(darktablerc, sizeof(darktablerc), "%s/darktablerc", datadir); // initialize the config backend. this needs to be done first... darktable.conf = (dt_conf_t *)calloc(1, sizeof(dt_conf_t)); dt_conf_init(darktable.conf, darktablerc, config_override); g_slist_free_full(config_override, g_free); // set the interface language const gchar *lang = dt_conf_get_string("ui_last/gui_language"); #if defined(_WIN32) // get the default locale if no language preference was specified in the config file if(lang == NULL || lang[0] == '\0') { const wchar_t *wcLocaleName = NULL; wcLocaleName = dtwin_get_locale(); if(wcLocaleName != NULL) { gchar *langLocale; langLocale = g_utf16_to_utf8(wcLocaleName, -1, NULL, NULL, NULL); if(langLocale != NULL) { g_free((gchar *)lang); lang = g_strdup(langLocale); } } } #endif // defined (_WIN32) if(lang != NULL && lang[0] != '\0') { g_setenv("LANGUAGE", lang, 1); if(setlocale(LC_ALL, lang) != NULL) gtk_disable_setlocale(); setlocale(LC_MESSAGES, lang); g_setenv("LANG", lang, 1); } g_free((gchar *)lang); // we need this REALLY early so that error messages can be shown, however after gtk_disable_setlocale if(init_gui) { #ifdef GDK_WINDOWING_WAYLAND // There are currently bad interactions with Wayland (drop-downs // are very narrow, scroll events lost). Until this is fixed, give // priority to the XWayland backend for Wayland users. gdk_set_allowed_backends("x11,*"); #endif gtk_init(&argc, &argv); } // detect cpu features and decide which codepaths to enable dt_codepaths_init(); // get the list of color profiles darktable.color_profiles = dt_colorspaces_init(); // initialize the database darktable.db = dt_database_init(dbfilename_from_command, load_data); if(darktable.db == NULL) { printf("ERROR : cannot open database\n"); return 1; } else if(!dt_database_get_lock_acquired(darktable.db)) { gboolean image_loaded_elsewhere = FALSE; #ifndef MAC_INTEGRATION // send the images to the other instance via dbus fprintf(stderr, "trying to open the images in the running instance\n"); GDBusConnection *connection = NULL; for(int i = 1; i < argc; i++) { // make the filename absolute ... if(argv[i] == NULL || *argv[i] == '\0') continue; gchar *filename = dt_util_normalize_path(argv[i]); if(filename == NULL) continue; if(!connection) connection = g_bus_get_sync(G_BUS_TYPE_SESSION, NULL, NULL); // ... and send it to the running instance of darktable image_loaded_elsewhere = g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable", "org.darktable.service.Remote", "Open", g_variant_new("(s)", filename), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL) != NULL; g_free(filename); } if(connection) g_object_unref(connection); #endif if(!image_loaded_elsewhere) dt_database_show_error(darktable.db); return 1; } // Initialize the signal system darktable.signals = dt_control_signal_init(); // Make sure that the database and xmp files are in sync // We need conf and db to be up and running for that which is the case here. // FIXME: is this also useful in non-gui mode? GList *changed_xmp_files = NULL; if(init_gui && dt_conf_get_bool("run_crawler_on_start")) { changed_xmp_files = dt_control_crawler_run(); } if(init_gui) { dt_control_init(darktable.control); } else { if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:")) dt_gui_presets_init(); // init preset db schema. darktable.control->running = 0; darktable.control->accelerators = NULL; dt_pthread_mutex_init(&darktable.control->run_mutex, NULL); } // initialize collection query darktable.collection = dt_collection_new(NULL); /* initialize selection */ darktable.selection = dt_selection_new(); /* capabilities set to NULL */ darktable.capabilities = NULL; // Initialize the password storage engine darktable.pwstorage = dt_pwstorage_new(); darktable.guides = dt_guides_init(); #ifdef HAVE_GRAPHICSMAGICK /* GraphicsMagick init */ InitializeMagick(darktable.progname); // *SIGH* dt_set_signal_handlers(); #endif darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t)); #ifdef HAVE_OPENCL dt_opencl_init(darktable.opencl, exclude_opencl, print_statistics); #endif darktable.points = (dt_points_t *)calloc(1, sizeof(dt_points_t)); dt_points_init(darktable.points, dt_get_num_threads()); darktable.noiseprofile_parser = dt_noiseprofile_init(noiseprofiles_from_command); // must come before mipmap_cache, because that one will need to access // image dimensions stored in here: darktable.image_cache = (dt_image_cache_t *)calloc(1, sizeof(dt_image_cache_t)); dt_image_cache_init(darktable.image_cache); darktable.mipmap_cache = (dt_mipmap_cache_t *)calloc(1, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); // The GUI must be initialized before the views, because the init() // functions of the views depend on darktable.control->accels_* to register // their keyboard accelerators if(init_gui) { darktable.gui = (dt_gui_gtk_t *)calloc(1, sizeof(dt_gui_gtk_t)); if(dt_gui_gtk_init(darktable.gui)) return 1; dt_bauhaus_init(); } else darktable.gui = NULL; darktable.view_manager = (dt_view_manager_t *)calloc(1, sizeof(dt_view_manager_t)); dt_view_manager_init(darktable.view_manager); // check whether we were able to load darkroom view. if we failed, we'll crash everywhere later on. if(!darktable.develop) return 1; darktable.imageio = (dt_imageio_t *)calloc(1, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); // load the darkroom mode plugins once: dt_iop_load_modules_so(); if(init_gui) { #ifdef HAVE_GPHOTO2 // Initialize the camera control. // this is done late so that the gui can react to the signal sent but before switching to lighttable! darktable.camctl = dt_camctl_new(); #endif darktable.lib = (dt_lib_t *)calloc(1, sizeof(dt_lib_t)); dt_lib_init(darktable.lib); dt_gui_gtk_load_config(); // init the gui part of views dt_view_manager_gui_init(darktable.view_manager); // Loading the keybindings char keyfile[PATH_MAX] = { 0 }; // First dump the default keymapping snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc_default", datadir); gtk_accel_map_save(keyfile); // Removing extraneous semi-colons from the default keymap strip_semicolons_from_keymap(keyfile); // Then load any modified keys if available snprintf(keyfile, sizeof(keyfile), "%s/keyboardrc", datadir); if(g_file_test(keyfile, G_FILE_TEST_EXISTS)) gtk_accel_map_load(keyfile); else gtk_accel_map_save(keyfile); // Save the default keymap if none is present // initialize undo struct darktable.undo = dt_undo_init(); } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] after successful startup\n"); dt_print_mem_usage(); } dt_image_local_copy_synch(); /* init lua last, since it's user made stuff it must be in the real environment */ #ifdef USE_LUA dt_lua_init(darktable.lua_state.state, lua_command); #endif if(init_gui) { const char *mode = "lighttable"; // april 1st: you have to earn using dt first! or know that you can switch views with keyboard shortcuts time_t now; time(&now); struct tm lt; localtime_r(&now, <); if(lt.tm_mon == 3 && lt.tm_mday == 1) mode = "knight"; // we have to call dt_ctl_switch_mode_to() here already to not run into a lua deadlock. // having another call later is ok dt_ctl_switch_mode_to(mode); #ifndef MAC_INTEGRATION // load image(s) specified on cmdline. // this has to happen after lua is initialized as image import can run lua code // If only one image is listed, attempt to load it in darkroom int last_id = 0; gboolean only_single_images = TRUE; int loaded_images = 0; for(int i = 1; i < argc; i++) { gboolean single_image = FALSE; if(argv[i] == NULL || *argv[i] == '\0') continue; int new_id = dt_load_from_string(argv[i], FALSE, &single_image); if(new_id > 0) { last_id = new_id; loaded_images++; if(!single_image) only_single_images = FALSE; } } if(loaded_images == 1 && only_single_images) { dt_control_set_mouse_over_id(last_id); dt_ctl_switch_mode_to("darkroom"); } #endif } // last but not least construct the popup that asks the user about images whose xmp files are newer than the // db entry if(init_gui && changed_xmp_files) { dt_control_crawler_show_image_list(changed_xmp_files); } dt_print(DT_DEBUG_CONTROL, "[init] startup took %f seconds\n", dt_get_wtime() - start_wtime); return 0; }
void dt_gaussian_blur(dt_gaussian_t *g, const float *const in, float *const out) { const int width = g->width; const int height = g->height; const int ch = g->channels; float a0, a1, a2, a3, b1, b2, coefp, coefn; compute_gauss_params(g->sigma, g->order, &a0, &a1, &a2, &a3, &b1, &b2, &coefp, &coefn); float *const temp = g->buf; float *const Labmax = g->max; float *const Labmin = g->min; float *const buf = malloc((size_t)9 * ch * dt_get_num_threads() * sizeof(float)); // vertical blur column by column #ifdef _OPENMP #pragma omp parallel for default(none) shared(a0, a1, a2, a3, b1, b2, coefp, coefn) schedule(static) #endif for(int i = 0; i < width; i++) { const int threadnum = dt_get_thread_num(); float *xp = buf + (size_t)9 * ch * threadnum + 0; float *yb = buf + (size_t)9 * ch * threadnum + 1; float *yp = buf + (size_t)9 * ch * threadnum + 2; float *xc = buf + (size_t)9 * ch * threadnum + 3; float *yc = buf + (size_t)9 * ch * threadnum + 4; float *xn = buf + (size_t)9 * ch * threadnum + 5; float *xa = buf + (size_t)9 * ch * threadnum + 6; float *yn = buf + (size_t)9 * ch * threadnum + 7; float *ya = buf + (size_t)9 * ch * threadnum + 8; // forward filter for(int k = 0; k < ch; k++) { xp[k] = CLAMPF(in[(size_t)i * ch + k], Labmin[k], Labmax[k]); yb[k] = xp[k] * coefp; yp[k] = yb[k]; xc[k] = yc[k] = xn[k] = xa[k] = yn[k] = ya[k] = 0.0f; } for(int j = 0; j < height; j++) { size_t offset = ((size_t)j * width + i) * ch; for(int k = 0; k < ch; k++) { xc[k] = CLAMPF(in[offset + k], Labmin[k], Labmax[k]); yc[k] = (a0 * xc[k]) + (a1 * xp[k]) - (b1 * yp[k]) - (b2 * yb[k]); temp[offset + k] = yc[k]; xp[k] = xc[k]; yb[k] = yp[k]; yp[k] = yc[k]; } } // backward filter for(int k = 0; k < ch; k++) { xn[k] = CLAMPF(in[((size_t)(height - 1) * width + i) * ch + k], Labmin[k], Labmax[k]); xa[k] = xn[k]; yn[k] = xn[k] * coefn; ya[k] = yn[k]; } for(int j = height - 1; j > -1; j--) { size_t offset = ((size_t)j * width + i) * ch; for(int k = 0; k < ch; k++) { xc[k] = CLAMPF(in[offset + k], Labmin[k], Labmax[k]); yc[k] = (a2 * xn[k]) + (a3 * xa[k]) - (b1 * yn[k]) - (b2 * ya[k]); xa[k] = xn[k]; xn[k] = xc[k]; ya[k] = yn[k]; yn[k] = yc[k]; temp[offset + k] += yc[k]; } } } // horizontal blur line by line #ifdef _OPENMP #pragma omp parallel for default(none) shared(a0, a1, a2, a3, b1, b2, coefp, coefn) schedule(static) #endif for(int j = 0; j < height; j++) { const int threadnum = dt_get_thread_num(); float *xp = buf + (size_t)9 * ch * threadnum + 0; float *yb = buf + (size_t)9 * ch * threadnum + 1; float *yp = buf + (size_t)9 * ch * threadnum + 2; float *xc = buf + (size_t)9 * ch * threadnum + 3; float *yc = buf + (size_t)9 * ch * threadnum + 4; float *xn = buf + (size_t)9 * ch * threadnum + 5; float *xa = buf + (size_t)9 * ch * threadnum + 6; float *yn = buf + (size_t)9 * ch * threadnum + 7; float *ya = buf + (size_t)9 * ch * threadnum + 8; // forward filter for(int k = 0; k < ch; k++) { xp[k] = CLAMPF(temp[(size_t)j * width * ch + k], Labmin[k], Labmax[k]); yb[k] = xp[k] * coefp; yp[k] = yb[k]; xc[k] = yc[k] = xn[k] = xa[k] = yn[k] = ya[k] = 0.0f; } for(int i = 0; i < width; i++) { size_t offset = ((size_t)j * width + i) * ch; for(int k = 0; k < ch; k++) { xc[k] = CLAMPF(temp[offset + k], Labmin[k], Labmax[k]); yc[k] = (a0 * xc[k]) + (a1 * xp[k]) - (b1 * yp[k]) - (b2 * yb[k]); out[offset + k] = yc[k]; xp[k] = xc[k]; yb[k] = yp[k]; yp[k] = yc[k]; } } // backward filter for(int k = 0; k < ch; k++) { xn[k] = CLAMPF(temp[((size_t)(j + 1) * width - 1) * ch + k], Labmin[k], Labmax[k]); xa[k] = xn[k]; yn[k] = xn[k] * coefn; ya[k] = yn[k]; } for(int i = width - 1; i > -1; i--) { size_t offset = ((size_t)j * width + i) * ch; for(int k = 0; k < ch; k++) { xc[k] = CLAMPF(temp[offset + k], Labmin[k], Labmax[k]); yc[k] = (a2 * xn[k]) + (a3 * xa[k]) - (b1 * yn[k]) - (b2 * ya[k]); xa[k] = xn[k]; xn[k] = xc[k]; ya[k] = yn[k]; yn[k] = yc[k]; out[offset + k] += yc[k]; } } } free(buf); }
int dt_init(int argc, char *argv[], const int init_gui) { // make everything go a lot faster. _MM_SET_FLUSH_ZERO_MODE(_MM_FLUSH_ZERO_ON); #ifndef __APPLE__ _dt_sigsegv_old_handler = signal(SIGSEGV,&_dt_sigsegv_handler); #endif #ifndef __SSE2__ fprintf(stderr, "[dt_init] unfortunately we depend on SSE2 instructions at this time.\n"); fprintf(stderr, "[dt_init] please contribute a backport patch (or buy a newer processor).\n"); return 1; #endif #ifdef M_MMAP_THRESHOLD mallopt(M_MMAP_THRESHOLD,128*1024) ; /* use mmap() for large allocations */ #endif bindtextdomain (GETTEXT_PACKAGE, DARKTABLE_LOCALEDIR); bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); textdomain (GETTEXT_PACKAGE); // init all pointers to 0: memset(&darktable, 0, sizeof(darktable_t)); darktable.progname = argv[0]; // database gchar *dbfilename_from_command = NULL; char *datadir_from_command = NULL; char *moduledir_from_command = NULL; char *tmpdir_from_command = NULL; char *configdir_from_command = NULL; char *cachedir_from_command = NULL; darktable.num_openmp_threads = 1; #ifdef _OPENMP darktable.num_openmp_threads = omp_get_num_procs(); #endif darktable.unmuted = 0; GSList *images_to_load = NULL; for(int k=1; k<argc; k++) { if(argv[k][0] == '-') { if(!strcmp(argv[k], "--help")) { return usage(argv[0]); } if(!strcmp(argv[k], "-h")) { return usage(argv[0]); } else if(!strcmp(argv[k], "--version")) { printf("this is "PACKAGE_STRING"\ncopyright (c) 2009-2013 johannes hanika\n"PACKAGE_BUGREPORT"\n"); return 1; } else if(!strcmp(argv[k], "--library")) { dbfilename_from_command = argv[++k]; } else if(!strcmp(argv[k], "--datadir")) { datadir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--moduledir")) { moduledir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--tmpdir")) { tmpdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--configdir")) { configdir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--cachedir")) { cachedir_from_command = argv[++k]; } else if(!strcmp(argv[k], "--localedir")) { bindtextdomain (GETTEXT_PACKAGE, argv[++k]); } else if(argv[k][1] == 'd' && argc > k+1) { if(!strcmp(argv[k+1], "all")) darktable.unmuted = 0xffffffff; // enable all debug information else if(!strcmp(argv[k+1], "cache")) darktable.unmuted |= DT_DEBUG_CACHE; // enable debugging for lib/film/cache module else if(!strcmp(argv[k+1], "control")) darktable.unmuted |= DT_DEBUG_CONTROL; // enable debugging for scheduler module else if(!strcmp(argv[k+1], "dev")) darktable.unmuted |= DT_DEBUG_DEV; // develop module else if(!strcmp(argv[k+1], "fswatch")) darktable.unmuted |= DT_DEBUG_FSWATCH; // fswatch module else if(!strcmp(argv[k+1], "camctl")) darktable.unmuted |= DT_DEBUG_CAMCTL; // camera control module else if(!strcmp(argv[k+1], "perf")) darktable.unmuted |= DT_DEBUG_PERF; // performance measurements else if(!strcmp(argv[k+1], "pwstorage")) darktable.unmuted |= DT_DEBUG_PWSTORAGE; // pwstorage module else if(!strcmp(argv[k+1], "opencl")) darktable.unmuted |= DT_DEBUG_OPENCL; // gpu accel via opencl else if(!strcmp(argv[k+1], "sql")) darktable.unmuted |= DT_DEBUG_SQL; // SQLite3 queries else if(!strcmp(argv[k+1], "memory")) darktable.unmuted |= DT_DEBUG_MEMORY; // some stats on mem usage now and then. else if(!strcmp(argv[k+1], "lighttable")) darktable.unmuted |= DT_DEBUG_LIGHTTABLE; // lighttable related stuff. else if(!strcmp(argv[k+1], "nan")) darktable.unmuted |= DT_DEBUG_NAN; // check for NANs when processing the pipe. else return usage(argv[0]); k ++; } else if(argv[k][1] == 't' && argc > k+1) { darktable.num_openmp_threads = CLAMP(atol(argv[k+1]), 1, 100); printf("[dt_init] using %d threads for openmp parallel sections\n", darktable.num_openmp_threads); k ++; } } #ifndef MAC_INTEGRATION else { images_to_load = g_slist_append(images_to_load, argv[k]); } #endif } if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] at startup\n"); dt_print_mem_usage(); } #ifdef _OPENMP omp_set_num_threads(darktable.num_openmp_threads); #endif dt_loc_init_datadir(datadir_from_command); dt_loc_init_plugindir(moduledir_from_command); if(dt_loc_init_tmp_dir(tmpdir_from_command)) { printf(_("ERROR : invalid temporary directory : %s\n"),darktable.tmpdir); return usage(argv[0]); } dt_loc_init_user_config_dir(configdir_from_command); dt_loc_init_user_cache_dir(cachedir_from_command); #if !GLIB_CHECK_VERSION(2, 35, 0) g_type_init(); #endif // does not work, as gtk is not inited yet. // even if it were, it's a super bad idea to invoke gtk stuff from // a signal handler. /* check cput caps */ // dt_check_cpu(argc,argv); #ifdef HAVE_GEGL char geglpath[DT_MAX_PATH_LEN]; char datadir[DT_MAX_PATH_LEN]; dt_loc_get_datadir(datadir, DT_MAX_PATH_LEN); snprintf(geglpath, DT_MAX_PATH_LEN, "%s/gegl:/usr/lib/gegl-0.0", datadir); (void)setenv("GEGL_PATH", geglpath, 1); gegl_init(&argc, &argv); #endif // thread-safe init: dt_exif_init(); char datadir[DT_MAX_PATH_LEN]; dt_loc_get_user_config_dir (datadir,DT_MAX_PATH_LEN); char filename[DT_MAX_PATH_LEN]; snprintf(filename, DT_MAX_PATH_LEN, "%s/darktablerc", datadir); // intialize the config backend. this needs to be done first... darktable.conf = (dt_conf_t *)malloc(sizeof(dt_conf_t)); memset(darktable.conf, 0, sizeof(dt_conf_t)); dt_conf_init(darktable.conf, filename); // set the interface language const gchar* lang = dt_conf_get_string("ui_last/gui_language"); if(lang != NULL && lang[0] != '\0') { if(setlocale(LC_ALL, lang) != NULL) gtk_disable_setlocale(); } // initialize the database darktable.db = dt_database_init(dbfilename_from_command); if(darktable.db == NULL) { printf("ERROR : cannot open database\n"); return 1; } else if(dt_database_get_already_locked(darktable.db)) { // send the images to the other instance via dbus if(images_to_load) { GSList *p = images_to_load; // get a connection! GDBusConnection *connection = g_bus_get_sync(G_BUS_TYPE_SESSION,NULL, NULL); while (p != NULL) { // make the filename absolute ... gchar *filename = dt_make_path_absolute((gchar*)p->data); if(filename == NULL) continue; // ... and send it to the running instance of darktable g_dbus_connection_call_sync(connection, "org.darktable.service", "/darktable", "org.darktable.service.Remote", "Open", g_variant_new ("(s)", filename), NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL); p = g_slist_next(p); g_free(filename); } g_slist_free(images_to_load); g_object_unref(connection); } return 1; } // Initialize the signal system darktable.signals = dt_control_signal_init(); // Initialize the filesystem watcher darktable.fswatch=dt_fswatch_new(); #ifdef HAVE_GPHOTO2 // Initialize the camera control darktable.camctl=dt_camctl_new(); #endif // get max lighttable thumbnail size: darktable.thumbnail_width = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_width"), 200, 3000); darktable.thumbnail_height = CLAMPS(dt_conf_get_int("plugins/lighttable/thumbnail_height"), 200, 3000); // and make sure it can be mip-mapped all the way from mip4 to mip0 darktable.thumbnail_width /= 16; darktable.thumbnail_width *= 16; darktable.thumbnail_height /= 16; darktable.thumbnail_height *= 16; // Initialize the password storage engine darktable.pwstorage=dt_pwstorage_new(); // FIXME: move there into dt_database_t dt_pthread_mutex_init(&(darktable.db_insert), NULL); dt_pthread_mutex_init(&(darktable.plugin_threadsafe), NULL); dt_pthread_mutex_init(&(darktable.capabilities_threadsafe), NULL); darktable.control = (dt_control_t *)malloc(sizeof(dt_control_t)); memset(darktable.control, 0, sizeof(dt_control_t)); if(init_gui) { dt_control_init(darktable.control); } else { // this is in memory, so schema can't exist yet. if(dbfilename_from_command && !strcmp(dbfilename_from_command, ":memory:")) { dt_control_create_database_schema(); dt_gui_presets_init(); // also init preset db schema. } darktable.control->running = 0; darktable.control->accelerators = NULL; dt_pthread_mutex_init(&darktable.control->run_mutex, NULL); } // initialize collection query darktable.collection_listeners = NULL; darktable.collection = dt_collection_new(NULL); /* initialize sellection */ darktable.selection = dt_selection_new(); /* capabilities set to NULL */ darktable.capabilities = NULL; #ifdef HAVE_GRAPHICSMAGICK /* GraphicsMagick init */ InitializeMagick(darktable.progname); #endif darktable.opencl = (dt_opencl_t *)malloc(sizeof(dt_opencl_t)); memset(darktable.opencl, 0, sizeof(dt_opencl_t)); dt_opencl_init(darktable.opencl, argc, argv); darktable.blendop = (dt_blendop_t *)malloc(sizeof(dt_blendop_t)); memset(darktable.blendop, 0, sizeof(dt_blendop_t)); dt_develop_blend_init(darktable.blendop); darktable.points = (dt_points_t *)malloc(sizeof(dt_points_t)); memset(darktable.points, 0, sizeof(dt_points_t)); dt_points_init(darktable.points, dt_get_num_threads()); // must come before mipmap_cache, because that one will need to access // image dimensions stored in here: darktable.image_cache = (dt_image_cache_t *)malloc(sizeof(dt_image_cache_t)); memset(darktable.image_cache, 0, sizeof(dt_image_cache_t)); dt_image_cache_init(darktable.image_cache); darktable.mipmap_cache = (dt_mipmap_cache_t *)malloc(sizeof(dt_mipmap_cache_t)); memset(darktable.mipmap_cache, 0, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); // The GUI must be initialized before the views, because the init() // functions of the views depend on darktable.control->accels_* to register // their keyboard accelerators if(init_gui) { darktable.gui = (dt_gui_gtk_t *)malloc(sizeof(dt_gui_gtk_t)); memset(darktable.gui,0,sizeof(dt_gui_gtk_t)); if(dt_gui_gtk_init(darktable.gui, argc, argv)) return 1; dt_bauhaus_init(); } else darktable.gui = NULL; darktable.view_manager = (dt_view_manager_t *)malloc(sizeof(dt_view_manager_t)); memset(darktable.view_manager, 0, sizeof(dt_view_manager_t)); dt_view_manager_init(darktable.view_manager); // load the darkroom mode plugins once: dt_iop_load_modules_so(); if(init_gui) { darktable.lib = (dt_lib_t *)malloc(sizeof(dt_lib_t)); memset(darktable.lib, 0, sizeof(dt_lib_t)); dt_lib_init(darktable.lib); dt_control_load_config(darktable.control); g_strlcpy(darktable.control->global_settings.dbname, filename, 512); // overwrite if relocated. } darktable.imageio = (dt_imageio_t *)malloc(sizeof(dt_imageio_t)); memset(darktable.imageio, 0, sizeof(dt_imageio_t)); dt_imageio_init(darktable.imageio); if(init_gui) { // Loading the keybindings char keyfile[DT_MAX_PATH_LEN]; // First dump the default keymapping snprintf(keyfile, DT_MAX_PATH_LEN, "%s/keyboardrc_default", datadir); gtk_accel_map_save(keyfile); // Removing extraneous semi-colons from the default keymap strip_semicolons_from_keymap(keyfile); // Then load any modified keys if available snprintf(keyfile, DT_MAX_PATH_LEN, "%s/keyboardrc", datadir); if(g_file_test(keyfile, G_FILE_TEST_EXISTS)) gtk_accel_map_load(keyfile); else gtk_accel_map_save(keyfile); // Save the default keymap if none is present // I doubt that connecting to dbus for darktable-cli makes sense darktable.dbus = dt_dbus_init(); // initialize undo struct darktable.undo = dt_undo_init(); // load image(s) specified on cmdline int id = 0; if(images_to_load) { // If only one image is listed, attempt to load it in darkroom gboolean load_in_dr = (g_slist_next(images_to_load) == NULL); GSList *p = images_to_load; while (p != NULL) { // don't put these function calls into MAX(), the macro will evaluate // it twice (and happily deadlock, in this particular case) int newid = dt_load_from_string((gchar*)p->data, load_in_dr); id = MAX(id, newid); p = g_slist_next(p); } if (!load_in_dr || id == 0) dt_ctl_switch_mode_to(DT_LIBRARY); g_slist_free(images_to_load); } else dt_ctl_switch_mode_to(DT_LIBRARY); } /* start the indexer background job */ dt_control_start_indexer(); if(darktable.unmuted & DT_DEBUG_MEMORY) { fprintf(stderr, "[memory] after successful startup\n"); dt_print_mem_usage(); } return 0; }
/** process, all real work is done here. */ void process (struct dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, void *ivoid, void *ovoid, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out) { // this is called for preview and full pipe separately, each with its own pixelpipe piece. // get our data struct: dt_iop_nlmeans_params_t *d = (dt_iop_nlmeans_params_t *)piece->data; // adjust to zoom size: const int P = ceilf(3 * roi_in->scale / piece->iscale); // pixel filter size const int K = ceilf(7 * roi_in->scale / piece->iscale); // nbhood if(P <= 1) { // nothing to do from this distance: memcpy (ovoid, ivoid, sizeof(float)*4*roi_out->width*roi_out->height); return; } // adjust to Lab, make L more important // float max_L = 100.0f, max_C = 256.0f; // float nL = 1.0f/(d->luma*max_L), nC = 1.0f/(d->chroma*max_C); float max_L = 120.0f, max_C = 512.0f; float nL = 1.0f/max_L, nC = 1.0f/max_C; const float norm2[4] = { nL*nL, nC*nC, nC*nC, 1.0f }; float *Sa = dt_alloc_align(64, sizeof(float)*roi_out->width*dt_get_num_threads()); // we want to sum up weights in col[3], so need to init to 0: memset(ovoid, 0x0, sizeof(float)*roi_out->width*roi_out->height*4); // for each shift vector for(int kj=-K;kj<=K;kj++) { for(int ki=-K;ki<=K;ki++) { int inited_slide = 0; // don't construct summed area tables but use sliding window! (applies to cpu version res < 1k only, or else we will add up errors) // do this in parallel with a little threading overhead. could parallelize the outer loops with a bit more memory #ifdef _OPENMP # pragma omp parallel for schedule(static) default(none) firstprivate(inited_slide) shared(kj, ki, roi_out, roi_in, ivoid, ovoid, Sa) #endif for(int j=0; j<roi_out->height; j++) { if(j+kj < 0 || j+kj >= roi_out->height) continue; float *S = Sa + dt_get_thread_num() * roi_out->width; const float *ins = ((float *)ivoid) + 4*(roi_in->width *(j+kj) + ki); float *out = ((float *)ovoid) + 4*roi_out->width*j; const int Pm = MIN(MIN(P, j+kj), j); const int PM = MIN(MIN(P, roi_out->height-1-j-kj), roi_out->height-1-j); // first line of every thread // TODO: also every once in a while to assert numerical precision! if(!inited_slide) { // sum up a line memset(S, 0x0, sizeof(float)*roi_out->width); for(int jj=-Pm;jj<=PM;jj++) { int i = MAX(0, -ki); float *s = S + i; const float *inp = ((float *)ivoid) + 4*i + 4* roi_in->width *(j+jj); const float *inps = ((float *)ivoid) + 4*i + 4*(roi_in->width *(j+jj+kj) + ki); const int last = roi_out->width + MIN(0, -ki); for(; i<last; i++, inp+=4, inps+=4, s++) { for(int k=0;k<3;k++) s[0] += (inp[k] - inps[k])*(inp[k] - inps[k]) * norm2[k]; } } // only reuse this if we had a full stripe if(Pm == P && PM == P) inited_slide = 1; } // sliding window for this line: float *s = S; float slide = 0.0f; // sum up the first -P..P for(int i=0;i<2*P+1;i++) slide += s[i]; for(int i=0; i<roi_out->width; i++) { if(i-P > 0 && i+P<roi_out->width) slide += s[P] - s[-P-1]; if(i+ki >= 0 && i+ki < roi_out->width) { const __m128 iv = { ins[0], ins[1], ins[2], 1.0f }; _mm_store_ps(out, _mm_load_ps(out) + iv * _mm_set1_ps(gh(slide))); } s ++; ins += 4; out += 4; } if(inited_slide && j+P+1+MAX(0,kj) < roi_out->height) { // sliding window in j direction: int i = MAX(0, -ki); float *s = S + i; const float *inp = ((float *)ivoid) + 4*i + 4* roi_in->width *(j+P+1); const float *inps = ((float *)ivoid) + 4*i + 4*(roi_in->width *(j+P+1+kj) + ki); const float *inm = ((float *)ivoid) + 4*i + 4* roi_in->width *(j-P); const float *inms = ((float *)ivoid) + 4*i + 4*(roi_in->width *(j-P+kj) + ki); const int last = roi_out->width + MIN(0, -ki); for(; ((unsigned long)s & 0xf) != 0 && i<last; i++, inp+=4, inps+=4, inm+=4, inms+=4, s++) { float stmp = s[0]; for(int k=0;k<3;k++) stmp += ((inp[k] - inps[k])*(inp[k] - inps[k]) - (inm[k] - inms[k])*(inm[k] - inms[k])) * norm2[k]; s[0] = stmp; } /* Process most of the line 4 pixels at a time */ for(; i<last-4; i+=4, inp+=16, inps+=16, inm+=16, inms+=16, s+=4) { __m128 sv = _mm_load_ps(s); const __m128 inp1 = _mm_load_ps(inp) - _mm_load_ps(inps); const __m128 inp2 = _mm_load_ps(inp+4) - _mm_load_ps(inps+4); const __m128 inp3 = _mm_load_ps(inp+8) - _mm_load_ps(inps+8); const __m128 inp4 = _mm_load_ps(inp+12) - _mm_load_ps(inps+12); const __m128 inp12lo = _mm_unpacklo_ps(inp1,inp2); const __m128 inp34lo = _mm_unpacklo_ps(inp3,inp4); const __m128 inp12hi = _mm_unpackhi_ps(inp1,inp2); const __m128 inp34hi = _mm_unpackhi_ps(inp3,inp4); const __m128 inpv0 = _mm_movelh_ps(inp12lo,inp34lo); sv += inpv0*inpv0 * _mm_set1_ps(norm2[0]); const __m128 inpv1 = _mm_movehl_ps(inp34lo,inp12lo); sv += inpv1*inpv1 * _mm_set1_ps(norm2[1]); const __m128 inpv2 = _mm_movelh_ps(inp12hi,inp34hi); sv += inpv2*inpv2 * _mm_set1_ps(norm2[2]); const __m128 inm1 = _mm_load_ps(inm) - _mm_load_ps(inms); const __m128 inm2 = _mm_load_ps(inm+4) - _mm_load_ps(inms+4); const __m128 inm3 = _mm_load_ps(inm+8) - _mm_load_ps(inms+8); const __m128 inm4 = _mm_load_ps(inm+12) - _mm_load_ps(inms+12); const __m128 inm12lo = _mm_unpacklo_ps(inm1,inm2); const __m128 inm34lo = _mm_unpacklo_ps(inm3,inm4); const __m128 inm12hi = _mm_unpackhi_ps(inm1,inm2); const __m128 inm34hi = _mm_unpackhi_ps(inm3,inm4); const __m128 inmv0 = _mm_movelh_ps(inm12lo,inm34lo); sv -= inmv0*inmv0 * _mm_set1_ps(norm2[0]); const __m128 inmv1 = _mm_movehl_ps(inm34lo,inm12lo); sv -= inmv1*inmv1 * _mm_set1_ps(norm2[1]); const __m128 inmv2 = _mm_movelh_ps(inm12hi,inm34hi); sv -= inmv2*inmv2 * _mm_set1_ps(norm2[2]); _mm_store_ps(s, sv); } for(; i<last; i++, inp+=4, inps+=4, inm+=4, inms+=4, s++) { float stmp = s[0]; for(int k=0;k<3;k++) stmp += ((inp[k] - inps[k])*(inp[k] - inps[k]) - (inm[k] - inms[k])*(inm[k] - inms[k])) * norm2[k]; s[0] = stmp; } } else inited_slide = 0; } } } // normalize and apply chroma/luma blending // bias a bit towards higher values for low input values: const __m128 weight = _mm_set_ps(1.0f, powf(d->chroma, 0.6), powf(d->chroma, 0.6), powf(d->luma, 0.6)); const __m128 invert = _mm_sub_ps(_mm_set1_ps(1.0f), weight); #ifdef _OPENMP #pragma omp parallel for default(none) schedule(static) shared(ovoid,ivoid,roi_out,d) #endif for(int j=0; j<roi_out->height; j++) { float *out = ((float *)ovoid) + 4*roi_out->width*j; float *in = ((float *)ivoid) + 4*roi_out->width*j; for(int i=0; i<roi_out->width; i++) { _mm_store_ps(out, _mm_add_ps( _mm_mul_ps(_mm_load_ps(in), invert), _mm_mul_ps(_mm_load_ps(out), _mm_div_ps(weight, _mm_set1_ps(out[3]))))); out += 4; in += 4; } } // free shared tmp memory: free(Sa); }
static void color_picker_helper_4ch_parallel(const dt_iop_buffer_dsc_t *dsc, const float *const pixel, const dt_iop_roi_t *roi, const int *const box, float *const picked_color, float *const picked_color_min, float *const picked_color_max, const dt_iop_colorspace_type_t cst_to) { const int width = roi->width; const size_t size = ((box[3] - box[1]) * (box[2] - box[0])); const float w = 1.0f / (float)size; const int numthreads = dt_get_num_threads(); float *const mean = malloc((size_t)3 * numthreads * sizeof(float)); float *const mmin = malloc((size_t)3 * numthreads * sizeof(float)); float *const mmax = malloc((size_t)3 * numthreads * sizeof(float)); for(int n = 0; n < 3 * numthreads; n++) { mean[n] = 0.0f; mmin[n] = INFINITY; mmax[n] = -INFINITY; } #ifdef _OPENMP #pragma omp parallel default(none) #endif { const int tnum = dt_get_thread_num(); float *const tmean = mean + 3 * tnum; float *const tmmin = mmin + 3 * tnum; float *const tmmax = mmax + 3 * tnum; #ifdef _OPENMP #pragma omp for schedule(static) collapse(2) #endif for(size_t j = box[1]; j < box[3]; j++) { for(size_t i = box[0]; i < box[2]; i++) { const size_t k = 4 * (width * j + i); float Lab[3] = { pixel[k], pixel[k + 1], pixel[k + 2] }; if(cst_to == iop_cs_LCh) dt_Lab_2_LCH(pixel + k, Lab); if(cst_to == iop_cs_HSL) dt_RGB_2_HSL(pixel + k, Lab); tmean[0] += w * Lab[0]; tmean[1] += w * Lab[1]; tmean[2] += w * Lab[2]; tmmin[0] = fminf(tmmin[0], Lab[0]); tmmin[1] = fminf(tmmin[1], Lab[1]); tmmin[2] = fminf(tmmin[2], Lab[2]); tmmax[0] = fmaxf(tmmax[0], Lab[0]); tmmax[1] = fmaxf(tmmax[1], Lab[1]); tmmax[2] = fmaxf(tmmax[2], Lab[2]); } } } for(int n = 0; n < numthreads; n++) { for(int k = 0; k < 3; k++) { picked_color[k] += mean[3 * n + k]; picked_color_min[k] = fminf(picked_color_min[k], mmin[3 * n + k]); picked_color_max[k] = fmaxf(picked_color_max[k], mmax[3 * n + k]); } } free(mmax); free(mmin); free(mean); }
static void color_picker_helper_xtrans_parallel(const dt_iop_buffer_dsc_t *const dsc, const float *const pixel, const dt_iop_roi_t *const roi, const int *const box, float *const picked_color, float *const picked_color_min, float *const picked_color_max) { const int width = roi->width; const uint8_t(*const xtrans)[6] = (const uint8_t(*const)[6])dsc->xtrans; uint32_t weights[3] = { 0u, 0u, 0u }; const int numthreads = dt_get_num_threads(); float *const msum = malloc((size_t)3 * numthreads * sizeof(float)); float *const mmin = malloc((size_t)3 * numthreads * sizeof(float)); float *const mmax = malloc((size_t)3 * numthreads * sizeof(float)); uint32_t *const cnt = malloc((size_t)3 * numthreads * sizeof(uint32_t)); for(int n = 0; n < 3 * numthreads; n++) { msum[n] = 0.0f; mmin[n] = INFINITY; mmax[n] = -INFINITY; cnt[n] = 0u; } #ifdef _OPENMP #pragma omp parallel default(none) #endif { const int tnum = dt_get_thread_num(); float *const tsum = msum + 3 * tnum; float *const tmmin = mmin + 3 * tnum; float *const tmmax = mmax + 3 * tnum; uint32_t *const tcnt = cnt + 3 * tnum; #ifdef _OPENMP #pragma omp for schedule(static) collapse(2) #endif for(size_t j = box[1]; j < box[3]; j++) { for(size_t i = box[0]; i < box[2]; i++) { const int c = FCxtrans(j, i, roi, xtrans); const size_t k = width * j + i; const float v = pixel[k]; tsum[c] += v; tmmin[c] = fminf(tmmin[c], v); tmmax[c] = fmaxf(tmmax[c], v); tcnt[c]++; } } } for(int n = 0; n < numthreads; n++) { for(int c = 0; c < 3; c++) { picked_color[c] += msum[3 * n + c]; picked_color_min[c] = fminf(picked_color_min[c], mmin[3 * n + c]); picked_color_max[c] = fmaxf(picked_color_max[c], mmax[3 * n + c]); weights[c] += cnt[3 * n + c]; } } free(cnt); free(mmax); free(mmin); free(msum); // and finally normalize data. // X-Trans RGB weighting averages to 2:5:2 for each 3x3 cell for(int c = 0; c < 3; c++) { picked_color[c] /= (float)weights[c]; } }
static void color_picker_helper_bayer_parallel(const dt_iop_buffer_dsc_t *const dsc, const float *const pixel, const dt_iop_roi_t *const roi, const int *const box, float *const picked_color, float *const picked_color_min, float *const picked_color_max) { const int width = roi->width; const uint32_t filters = dsc->filters; uint32_t weights[4] = { 0u, 0u, 0u, 0u }; const int numthreads = dt_get_num_threads(); float *const msum = malloc((size_t)4 * numthreads * sizeof(float)); float *const mmin = malloc((size_t)4 * numthreads * sizeof(float)); float *const mmax = malloc((size_t)4 * numthreads * sizeof(float)); uint32_t *const cnt = malloc((size_t)4 * numthreads * sizeof(uint32_t)); for(int n = 0; n < 4 * numthreads; n++) { msum[n] = 0.0f; mmin[n] = INFINITY; mmax[n] = -INFINITY; cnt[n] = 0u; } #ifdef _OPENMP #pragma omp parallel default(none) #endif { const int tnum = dt_get_thread_num(); float *const tsum = msum + 4 * tnum; float *const tmmin = mmin + 4 * tnum; float *const tmmax = mmax + 4 * tnum; uint32_t *const tcnt = cnt + 4 * tnum; #ifdef _OPENMP #pragma omp for schedule(static) collapse(2) #endif for(size_t j = box[1]; j < box[3]; j++) { for(size_t i = box[0]; i < box[2]; i++) { const int c = FC(j + roi->y, i + roi->x, filters); const size_t k = width * j + i; const float v = pixel[k]; tsum[c] += v; tmmin[c] = fminf(tmmin[c], v); tmmax[c] = fmaxf(tmmax[c], v); tcnt[c]++; } } } for(int n = 0; n < numthreads; n++) { for(int c = 0; c < 4; c++) { picked_color[c] += msum[4 * n + c]; picked_color_min[c] = fminf(picked_color_min[c], mmin[4 * n + c]); picked_color_max[c] = fmaxf(picked_color_max[c], mmax[4 * n + c]); weights[c] += cnt[4 * n + c]; } } free(cnt); free(mmax); free(mmin); free(msum); // and finally normalize data. For bayer, there is twice as much green. for(int c = 0; c < 4; c++) { picked_color[c] = weights[c] ? (picked_color[c] / (float)weights[c]) : 0.0f; } }