1 /* This file is part of GEGL
2 *
3 * GEGL is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
7 *
8 * GEGL is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with GEGL; if not, see <https://www.gnu.org/licenses/>.
15 *
16 * Copyright 2003-2007 Calvin Williamson, Øyvind Kolås
17 * 2013 Daniel Sabo
18 */
19
20 #include "config.h"
21 #define __GEGL_INIT_C
22
23 #include <babl/babl.h>
24
25 #include <glib-object.h>
26 #include <glib/gstdio.h>
27 #include <glib/gi18n-lib.h>
28
29 #include <locale.h>
30
31 #include <stdlib.h>
32 #ifdef HAVE_UNISTD_H
33 #include <unistd.h>
34 #endif
35
36 #ifdef G_OS_WIN32
37
38 #include <windows.h>
39
40 static HMODULE hLibGeglModule = NULL;
41
42 /* DllMain prototype */
43 BOOL WINAPI DllMain (HINSTANCE hinstDLL,
44 DWORD fdwReason,
45 LPVOID lpvReserved);
46
47 BOOL WINAPI
DllMain(HINSTANCE hinstDLL,DWORD fdwReason,LPVOID lpvReserved)48 DllMain (HINSTANCE hinstDLL,
49 DWORD fdwReason,
50 LPVOID lpvReserved)
51 {
52 hLibGeglModule = hinstDLL;
53 return TRUE;
54 }
55
56 #endif
57
58
59 #include "gegl-debug.h"
60
61 guint gegl_debug_flags = 0;
62
63 #include "gegl-types.h"
64 #include "gegl-types-internal.h"
65 #include "gegl-instrument.h"
66 #include "gegl-init.h"
67 #include "gegl-init-private.h"
68 #include "module/geglmodule.h"
69 #include "module/geglmoduledb.h"
70 #include "buffer/gegl-buffer.h"
71 #include "operation/gegl-operation.h"
72 #include "operation/gegl-operations.h"
73 #include "operation/gegl-operation-handlers-private.h"
74 #include "buffer/gegl-buffer-private.h"
75 #include "buffer/gegl-buffer-iterator-private.h"
76 #include "buffer/gegl-buffer-swap-private.h"
77 #include "buffer/gegl-compression.h"
78 #include "buffer/gegl-tile-alloc.h"
79 #include "buffer/gegl-tile-backend-ram.h"
80 #include "buffer/gegl-tile-backend-file.h"
81 #include "gegl-config.h"
82 #include "gegl-stats.h"
83 #include "graph/gegl-node-private.h"
84 #include "gegl-random-private.h"
85 #include "gegl-parallel-private.h"
86
87 static gboolean gegl_post_parse_hook (GOptionContext *context,
88 GOptionGroup *group,
89 gpointer data,
90 GError **error);
91
92
93 static GeglConfig *config = NULL;
94
95 static GeglStats *stats = NULL;
96
97 static GeglModuleDB *module_db = NULL;
98
99 static glong global_time = 0;
100
101 static void load_module_path(gchar *path, GeglModuleDB *db);
102
103 static void
gegl_config_application_license_notify(GObject * gobject,GParamSpec * pspec,gpointer user_data)104 gegl_config_application_license_notify (GObject *gobject,
105 GParamSpec *pspec,
106 gpointer user_data)
107 {
108 GeglConfig *cfg = GEGL_CONFIG (gobject);
109 GSList *paths = gegl_get_default_module_paths ();
110
111 gegl_operations_set_licenses_from_string (cfg->application_license);
112
113 /* causes load of .so's that might have been skipped due to filename */
114 g_slist_foreach(paths, (GFunc)load_module_path, module_db);
115 g_slist_free_full (paths, g_free);
116 }
117
118
119 static void
gegl_config_use_opencl_notify(GObject * gobject,GParamSpec * pspec,gpointer user_data)120 gegl_config_use_opencl_notify (GObject *gobject,
121 GParamSpec *pspec,
122 gpointer user_data)
123 {
124 GeglConfig *cfg = GEGL_CONFIG (gobject);
125
126 g_signal_handlers_block_by_func (gobject,
127 gegl_config_use_opencl_notify,
128 NULL);
129
130 if (cfg->use_opencl)
131 {
132 gegl_cl_init (NULL);
133 }
134 else
135 {
136 gegl_cl_disable ();
137 }
138
139 cfg->use_opencl = gegl_cl_is_accelerated();
140
141 g_signal_handlers_unblock_by_func (gobject,
142 gegl_config_use_opencl_notify,
143 NULL);
144 }
145
146 static void
gegl_init_i18n(void)147 gegl_init_i18n (void)
148 {
149 static gboolean i18n_initialized = FALSE;
150
151 if (! i18n_initialized)
152 {
153 bindtextdomain (GETTEXT_PACKAGE, GEGL_LOCALEDIR);
154 bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
155
156 i18n_initialized = TRUE;
157 }
158 }
159
160 static GThread *main_thread = NULL;
161
gegl_is_main_thread(void)162 gboolean gegl_is_main_thread (void)
163 {
164 return g_thread_self () == main_thread;
165 }
166
167 void _gegl_init_u8_lut (void);
168
169 void
gegl_init(gint * argc,gchar *** argv)170 gegl_init (gint *argc,
171 gchar ***argv)
172 {
173 GOptionContext *context;
174 GError *error = NULL;
175 static gboolean initialized = FALSE;
176
177 if (initialized)
178 return;
179
180
181
182 initialized = TRUE;
183
184 context = g_option_context_new (NULL);
185 g_option_context_set_ignore_unknown_options (context, TRUE);
186 g_option_context_set_help_enabled (context, FALSE);
187 g_option_context_set_main_group (context, gegl_get_option_group ());
188
189 if (!g_option_context_parse (context, argc, argv, &error))
190 {
191 g_warning ("%s", error->message);
192 g_error_free (error);
193 }
194
195 g_option_context_free (context);
196 }
197
198 static gchar *cmd_gegl_swap = NULL;
199 static gchar *cmd_gegl_swap_compression = NULL;
200 static gchar *cmd_gegl_cache_size = NULL;
201 static gchar *cmd_gegl_chunk_size = NULL;
202 static gchar *cmd_gegl_quality = NULL;
203 static gchar *cmd_gegl_tile_size = NULL;
204 static gchar *cmd_gegl_threads = NULL;
205 static gboolean *cmd_gegl_disable_opencl = NULL;
206
207 static const GOptionEntry cmd_entries[]=
208 {
209 {
210 "gegl-swap", 0, 0,
211 G_OPTION_ARG_STRING, &cmd_gegl_swap,
212 N_("Where GEGL stores its swap"), "<uri>"
213 },
214 {
215 "gegl-swap-compression", 0, 0,
216 G_OPTION_ARG_STRING, &cmd_gegl_swap_compression,
217 N_("Compression algorithm used for data stored in the swap"), "<algorithm>"
218 },
219 {
220 "gegl-cache-size", 0, 0,
221 G_OPTION_ARG_STRING, &cmd_gegl_cache_size,
222 N_("How much memory to (approximately) use for caching imagery"), "<megabytes>"
223 },
224 {
225 "gegl-tile-size", 0, 0,
226 G_OPTION_ARG_STRING, &cmd_gegl_tile_size,
227 N_("Default size of tiles in GeglBuffers"), "<widthxheight>"
228 },
229 {
230 "gegl-chunk-size", 0, 0,
231 G_OPTION_ARG_STRING, &cmd_gegl_chunk_size,
232 N_("The count of pixels to compute simultaneously"), "pixel count"
233 },
234 {
235 "gegl-quality", 0, 0,
236 G_OPTION_ARG_STRING, &cmd_gegl_quality,
237 N_("The quality of rendering, a value between 0.0 (fast) and 1.0 (reference)"), "<quality>"
238 },
239 {
240 "gegl-threads", 0, 0,
241 G_OPTION_ARG_STRING, &cmd_gegl_threads,
242 N_("The number of concurrent processing threads to use"), "<threads>"
243 },
244 {
245 "gegl-disable-opencl", 0, 0,
246 G_OPTION_ARG_NONE, &cmd_gegl_disable_opencl,
247 N_("Disable OpenCL"), NULL
248 },
249 { NULL }
250 };
251
252 GOptionGroup *
gegl_get_option_group(void)253 gegl_get_option_group (void)
254 {
255 GOptionGroup *group;
256
257 gegl_init_i18n ();
258
259 group = g_option_group_new ("gegl", "GEGL Options", _("Show GEGL Options"),
260 NULL, NULL);
261 g_option_group_add_entries (group, cmd_entries);
262
263 g_option_group_set_parse_hooks (group, NULL, gegl_post_parse_hook);
264
265 return group;
266 }
267
268 static void
gegl_config_parse_env(GeglConfig * config)269 gegl_config_parse_env (GeglConfig *config)
270 {
271 if (g_getenv ("GEGL_MIPMAP_RENDERING"))
272 {
273 const gchar *value = g_getenv ("GEGL_MIPMAP_RENDERING");
274 if (!strcmp (value, "1")||
275 !strcmp (value, "true")||
276 !strcmp (value, "yes"))
277 g_object_set (config, "mipmap-rendering", TRUE, NULL);
278 else
279 g_object_set (config, "mipmap-rendering", FALSE, NULL);
280 }
281
282
283 if (g_getenv ("GEGL_QUALITY"))
284 {
285 const gchar *quality = g_getenv ("GEGL_QUALITY");
286
287 if (g_str_equal (quality, "fast"))
288 g_object_set (config, "quality", 0.0, NULL);
289 else if (g_str_equal (quality, "good"))
290 g_object_set (config, "quality", 0.5, NULL);
291 else if (g_str_equal (quality, "best"))
292 g_object_set (config, "quality", 1.0, NULL);
293 else
294 g_object_set (config, "quality", atof (quality), NULL);
295 }
296
297 if (g_getenv ("GEGL_CACHE_SIZE"))
298 {
299 g_object_set (config,
300 "tile-cache-size",
301 (guint64) atoll(g_getenv("GEGL_CACHE_SIZE")) * 1024 * 1024,
302 NULL);
303 }
304
305 if (g_getenv ("GEGL_CHUNK_SIZE"))
306 config->chunk_size = atoi(g_getenv("GEGL_CHUNK_SIZE"));
307
308 if (g_getenv ("GEGL_TILE_SIZE"))
309 {
310 const gchar *str = g_getenv ("GEGL_TILE_SIZE");
311 gint width;
312 gint height;
313 width = height = atoi(str);
314 str = strchr (str, 'x');
315 if (str)
316 height = atoi(str+1);
317 g_object_set (config,
318 "tile-width", width,
319 "tile-height", height,
320 NULL);
321 }
322
323 if (g_getenv ("GEGL_THREADS"))
324 {
325 _gegl_threads = atoi(g_getenv("GEGL_THREADS"));
326
327 if (_gegl_threads > GEGL_MAX_THREADS)
328 {
329 g_warning ("Tried to use %i threads, max is %i",
330 _gegl_threads, GEGL_MAX_THREADS);
331 _gegl_threads = GEGL_MAX_THREADS;
332 }
333 }
334
335 if (g_getenv ("GEGL_USE_OPENCL"))
336 {
337 const char *opencl_env = g_getenv ("GEGL_USE_OPENCL");
338
339 if (g_ascii_strcasecmp (opencl_env, "yes") == 0)
340 g_object_set (config, "use-opencl", TRUE, NULL);
341 else if (g_ascii_strcasecmp (opencl_env, "no") == 0)
342 gegl_cl_hard_disable ();
343 else if (g_ascii_strcasecmp (opencl_env, "cpu") == 0) {
344 gegl_cl_set_default_device_type (CL_DEVICE_TYPE_CPU);
345 g_object_set (config, "use-opencl", TRUE, NULL);
346 } else if (g_ascii_strcasecmp (opencl_env, "gpu") == 0) {
347 gegl_cl_set_default_device_type (CL_DEVICE_TYPE_GPU);
348 g_object_set (config, "use-opencl", TRUE, NULL);
349 } else if (g_ascii_strcasecmp (opencl_env, "accelerator") == 0) {
350 gegl_cl_set_default_device_type (CL_DEVICE_TYPE_ACCELERATOR);
351 g_object_set (config, "use-opencl", TRUE, NULL);
352 } else
353 g_warning ("Unknown value for GEGL_USE_OPENCL: %s", opencl_env);
354 }
355
356 if (g_getenv ("GEGL_SWAP"))
357 g_object_set (config, "swap", g_getenv ("GEGL_SWAP"), NULL);
358
359 if (g_getenv ("GEGL_SWAP_COMPRESSION"))
360 {
361 g_object_set (config,
362 "swap-compression", g_getenv ("GEGL_SWAP_COMPRESSION"),
363 NULL);
364 }
365 }
366
367 GeglConfig *
gegl_config(void)368 gegl_config (void)
369 {
370 if (!config)
371 config = g_object_new (GEGL_TYPE_CONFIG, NULL);
372
373 return config;
374 }
375
376 GeglStats *
gegl_stats(void)377 gegl_stats (void)
378 {
379 if (! stats)
380 stats = g_object_new (GEGL_TYPE_STATS, NULL);
381
382 return stats;
383 }
384
385 void
gegl_reset_stats(void)386 gegl_reset_stats (void)
387 {
388 gegl_stats_reset (gegl_stats ());
389 }
390
391 void
392 gegl_temp_buffer_free (void);
393
394 void
gegl_exit(void)395 gegl_exit (void)
396 {
397 if (!config)
398 {
399 g_warning("gegl_exit() called without matching call to gegl_init()");
400 return;
401 }
402
403 GEGL_INSTRUMENT_START()
404
405 gegl_tile_backend_swap_cleanup ();
406 gegl_tile_cache_destroy ();
407 gegl_operation_gtype_cleanup ();
408 gegl_operation_handlers_cleanup ();
409 gegl_compression_cleanup ();
410 gegl_random_cleanup ();
411 gegl_parallel_cleanup ();
412 gegl_buffer_swap_cleanup ();
413 gegl_tile_alloc_cleanup ();
414 gegl_cl_cleanup ();
415
416 gegl_temp_buffer_free ();
417
418 g_clear_object (&module_db);
419
420 babl_exit ();
421
422 GEGL_INSTRUMENT_END ("gegl", "gegl_exit")
423
424 /* used when tracking buffer and tile leaks */
425 if (g_getenv ("GEGL_DEBUG_BUFS") != NULL)
426 {
427 gegl_buffer_stats ();
428 gegl_tile_backend_ram_stats ();
429 gegl_tile_backend_file_stats ();
430 }
431 global_time = gegl_ticks () - global_time;
432 gegl_instrument ("gegl", "gegl", global_time);
433
434 if (gegl_instrument_enabled)
435 {
436 g_printf ("\n%s", gegl_instrument_utf8 ());
437 }
438
439 if (gegl_buffer_leaks ())
440 {
441 g_printf ("EEEEeEeek! %i GeglBuffers leaked\n", gegl_buffer_leaks ());
442 #ifdef GEGL_ENABLE_DEBUG
443 if (!(gegl_debug_flags & GEGL_DEBUG_BUFFER_ALLOC))
444 g_printerr ("To debug GeglBuffer leaks, set the environment "
445 "variable GEGL_DEBUG to \"buffer-alloc\"\n");
446 #endif
447 }
448
449 g_clear_object (&config);
450 global_time = 0;
451 }
452
453 void
gegl_get_version(int * major,int * minor,int * micro)454 gegl_get_version (int *major,
455 int *minor,
456 int *micro)
457 {
458 if (major != NULL)
459 *major = GEGL_MAJOR_VERSION;
460
461 if (minor != NULL)
462 *minor = GEGL_MINOR_VERSION;
463
464 if (micro != NULL)
465 *micro = GEGL_MICRO_VERSION;
466 }
467
468 void
gegl_load_module_directory(const gchar * path)469 gegl_load_module_directory (const gchar *path)
470 {
471 g_return_if_fail (g_file_test (path, G_FILE_TEST_IS_DIR));
472
473 gegl_module_db_load (module_db, path);
474 }
475
476
477 GSList *
gegl_get_default_module_paths(void)478 gegl_get_default_module_paths(void)
479 {
480 GSList *list = NULL;
481 gchar *module_path = NULL;
482
483 // GEGL_PATH
484 const gchar *gegl_path = g_getenv ("GEGL_PATH");
485 if (gegl_path)
486 {
487 list = g_slist_append (list, g_strdup (gegl_path));
488 return list;
489 }
490
491 // System library dir
492 #ifdef G_OS_WIN32
493 {
494 gchar *prefix;
495 prefix = g_win32_get_package_installation_directory_of_module ( hLibGeglModule );
496 module_path = g_build_filename (prefix, "lib", GEGL_LIBRARY, NULL);
497 g_free(prefix);
498 }
499 #else
500 module_path = g_build_filename (LIBDIR, GEGL_LIBRARY, NULL);
501 #endif
502 list = g_slist_append (list, module_path);
503
504 /* User data dir
505 * ~/.local/share/gegl-x.y/plug-ins */
506 module_path = g_build_filename (g_get_user_data_dir (),
507 GEGL_LIBRARY,
508 "plug-ins",
509 NULL);
510 g_mkdir_with_parents (module_path, S_IRUSR | S_IWUSR | S_IXUSR);
511 list = g_slist_append (list, module_path);
512
513 return list;
514 }
515
516 static void
load_module_path(gchar * path,GeglModuleDB * db)517 load_module_path(gchar *path, GeglModuleDB *db)
518 {
519 gegl_module_db_load (db, path);
520 }
521
522 static gboolean
gegl_post_parse_hook(GOptionContext * context,GOptionGroup * group,gpointer data,GError ** error)523 gegl_post_parse_hook (GOptionContext *context,
524 GOptionGroup *group,
525 gpointer data,
526 GError **error)
527 {
528 GeglConfig *config;
529
530 g_assert (global_time == 0);
531 global_time = gegl_ticks ();
532
533 if (g_getenv ("GEGL_DEBUG_TIME") != NULL)
534 gegl_instrument_enable ();
535
536 gegl_instrument ("gegl", "gegl_init", 0);
537
538 config = gegl_config ();
539
540 gegl_config_parse_env (config);
541
542 babl_init ();
543 _gegl_init_u8_lut ();
544
545 #ifdef GEGL_ENABLE_DEBUG
546 {
547 const char *env_string;
548 env_string = g_getenv ("GEGL_DEBUG");
549 if (env_string != NULL)
550 {
551 gegl_debug_flags =
552 g_parse_debug_string (env_string,
553 gegl_debug_keys,
554 G_N_ELEMENTS (gegl_debug_keys));
555 env_string = NULL;
556 }
557 }
558 #endif /* GEGL_ENABLE_DEBUG */
559
560 if (cmd_gegl_swap)
561 g_object_set (config, "swap", cmd_gegl_swap, NULL);
562 if (cmd_gegl_swap_compression)
563 g_object_set (config, "swap-compression", cmd_gegl_swap_compression, NULL);
564 if (cmd_gegl_quality)
565 config->quality = atof (cmd_gegl_quality);
566 if (cmd_gegl_cache_size)
567 {
568 g_object_set (config,
569 "tile-cache-size",
570 (guint64) atoll (cmd_gegl_cache_size) * 1024 * 1024,
571 NULL);
572 }
573 if (cmd_gegl_chunk_size)
574 config->chunk_size = atoi (cmd_gegl_chunk_size);
575 if (cmd_gegl_tile_size)
576 {
577 const gchar *str = cmd_gegl_tile_size;
578 gint width;
579 gint height;
580 width = height = atoi(str);
581 str = strchr (str, 'x');
582 if (str)
583 height = atoi(str+1);
584 g_object_set (config,
585 "tile-width", width,
586 "tile-height", height,
587 NULL);
588 }
589 if (cmd_gegl_threads)
590 {
591 _gegl_threads = atoi (cmd_gegl_threads);
592 if (_gegl_threads > GEGL_MAX_THREADS)
593 {
594 g_warning ("Tried to use %i threads, max is %i",
595 _gegl_threads, GEGL_MAX_THREADS);
596 _gegl_threads = GEGL_MAX_THREADS;
597 }
598 }
599 if (cmd_gegl_disable_opencl)
600 gegl_cl_hard_disable ();
601
602 GEGL_INSTRUMENT_START();
603
604 gegl_tile_alloc_init ();
605 gegl_buffer_swap_init ();
606 gegl_parallel_init ();
607 gegl_compression_init ();
608 gegl_operation_gtype_init ();
609 gegl_tile_cache_init ();
610
611 if (!module_db)
612 {
613 GSList *paths = gegl_get_default_module_paths ();
614 module_db = gegl_module_db_new (FALSE);
615 g_slist_foreach(paths, (GFunc)load_module_path, module_db);
616 g_slist_free_full (paths, g_free);
617 }
618
619 GEGL_INSTRUMENT_END ("gegl_init", "load modules");
620
621 gegl_instrument ("gegl", "gegl_init", gegl_ticks () - global_time);
622
623 g_signal_connect (G_OBJECT (config),
624 "notify::use-opencl",
625 G_CALLBACK (gegl_config_use_opencl_notify),
626 NULL);
627 g_object_set (config, "use-opencl", config->use_opencl, NULL);
628
629 g_signal_connect (G_OBJECT (config),
630 "notify::application-license",
631 G_CALLBACK (gegl_config_application_license_notify),
632 NULL);
633 gegl_operations_set_licenses_from_string (config->application_license);
634
635 main_thread = g_thread_self ();
636
637 return TRUE;
638 }
639
640 gboolean
gegl_get_debug_enabled(void)641 gegl_get_debug_enabled (void)
642 {
643 #ifdef GEGL_ENABLE_DEBUG
644 return gegl_debug_flags != 0;
645 #else
646 return FALSE;
647 #endif
648 }
649