From b6c3e9f0754abcca694acff571e74ec37dd5f482 Mon Sep 17 00:00:00 2001 From: Hanno Schwalm Date: Sat, 15 Feb 2025 12:31:29 +0100 Subject: [PATCH 1/3] control system maintenance 1. don't expose implementation details. All functions using `dt_control_t` as an argument use and check it internally Allocation/free is done inside dt_control_init and `dt_control_cleanup()` Both functions work for en/disabled gui 2. simplified `dt_control_running()` 3. Removed `dt_control_job_set_state_callback` and `dt_control_job_wait` as not used 4. Use more const where possible 5. static function names have a leading underscore 6. add pending jobs infrastructure and `int dt_control_jobs_pending(void);` allowing to check for pending background jobs when darktable gui is closing, possibly give feedback to the user 7. add the queue name to some logs --- src/common/collection.c | 2 +- src/common/cups_print.c | 2 +- src/common/darktable.c | 43 +++--- src/common/film.c | 2 +- src/common/mipmap_cache.c | 4 +- src/control/control.c | 78 ++++++---- src/control/control.h | 49 +++--- src/control/jobs.c | 160 +++++++++----------- src/control/jobs.h | 25 ++-- src/control/jobs/control_jobs.c | 258 ++++++++++++++++---------------- src/control/jobs/control_jobs.h | 34 ++--- src/control/jobs/sidecar_jobs.c | 2 +- src/control/progress.c | 34 +++-- src/control/progress.h | 21 ++- src/develop/blend_gui.c | 4 +- src/develop/develop.c | 12 +- src/develop/masks/masks.c | 4 +- src/gui/gtk.c | 2 +- src/iop/clipping.c | 12 +- src/iop/crop.c | 10 +- src/iop/liquify.c | 9 +- src/iop/toneequal.c | 6 +- src/libs/backgroundjobs.c | 2 +- src/libs/camera.c | 2 +- src/libs/import.c | 2 +- src/libs/print_settings.c | 2 +- src/lua/gui.c | 8 +- src/lua/luastorage.c | 2 +- src/lua/print.c | 2 +- src/views/slideshow.c | 4 +- src/views/tethering.c | 2 +- 31 files changed, 387 insertions(+), 412 deletions(-) diff --git a/src/common/collection.c b/src/common/collection.c index c7323d024050..61d83176b7b7 100644 --- a/src/common/collection.c +++ b/src/common/collection.c @@ -2702,7 +2702,7 @@ gboolean dt_collection_hint_message_internal(void *message) } g_free(message); - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); return FALSE; } diff --git a/src/common/cups_print.c b/src/common/cups_print.c index 50dd62276ab8..25525dd338c7 100644 --- a/src/common/cups_print.c +++ b/src/common/cups_print.c @@ -214,7 +214,7 @@ void dt_printers_discovery(void (*cb)(dt_printer_info_t *pr, void *user_data), v prtctl->user_data = user_data; dt_control_job_set_params(job, prtctl, g_free); - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_BG, job); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_BG, job); } } diff --git a/src/common/darktable.c b/src/common/darktable.c index c4cb0c5aafcb..896173cd6b02 100644 --- a/src/common/darktable.c +++ b/src/common/darktable.c @@ -741,8 +741,7 @@ void dt_start_backtumbs_crawler(void) { // don't write thumbs if using memory database or on a non-sufficient system if(!darktable.backthumbs.running && darktable.backthumbs.capable) - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_BG, - _backthumbs_job_create()); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_BG, _backthumbs_job_create()); } static char *_get_version_string(void) @@ -916,15 +915,15 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load pthread_mutexattr_settype(&recursive_locking, PTHREAD_MUTEX_RECURSIVE); for(int k=0; krunning, DT_CONTROL_STATE_DISABLED); - dt_pthread_mutex_init(&darktable.control->log_mutex, NULL); } // import default styles from shared directory @@ -1737,8 +1731,7 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load darktable_splash_screen_set_progress(_("starting OpenCL")); darktable.opencl = (dt_opencl_t *)calloc(1, sizeof(dt_opencl_t)); if(init_gui) - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_BG, - _detect_opencl_job_create(exclude_opencl)); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_BG, _detect_opencl_job_create(exclude_opencl)); else dt_opencl_init(darktable.opencl, exclude_opencl, print_statistics); @@ -1892,8 +1885,7 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load // fire up a background job to import them after switching to // lighttable showing the filmroll for the first one _switch_to_new_filmroll(argv[1]); - dt_control_add_job(darktable.control, - DT_JOB_QUEUE_USER_BG, dt_pathlist_import_create(argc,argv)); + dt_control_add_job(DT_JOB_QUEUE_USER_BG, dt_pathlist_import_create(argc,argv)); } // there might be some info created in dt_configure_runtime_performance() for feedback @@ -2074,7 +2066,7 @@ void dt_cleanup() 5. After dt_control_shutdown() has finished we are sure there are no background threads running any more so we can safely close all mentioned subsystems and continue. */ - dt_control_shutdown(darktable.control); + dt_control_shutdown(); } #ifdef USE_LUA dt_lua_finalize(); @@ -2091,14 +2083,15 @@ void dt_cleanup() dt_imageio_cleanup(darktable.imageio); free(darktable.imageio); darktable.imageio = NULL; - dt_control_cleanup(darktable.control); - free(darktable.control); - darktable.control = NULL; + dt_control_cleanup(TRUE); dt_undo_cleanup(darktable.undo); darktable.undo = NULL; free(darktable.gui); darktable.gui = NULL; } + else + dt_control_cleanup(FALSE); + dt_image_cache_cleanup(darktable.image_cache); free(darktable.image_cache); diff --git a/src/common/film.c b/src/common/film.c index 52bb8731bec1..678dd761b99c 100644 --- a/src/common/film.c +++ b/src/common/film.c @@ -322,7 +322,7 @@ dt_filmid_t dt_film_import(const char *dirname) "DELETE FROM main.selected_images", NULL, NULL, NULL); // launch import job - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, dt_film_import1_create(film)); + dt_control_add_job(DT_JOB_QUEUE_USER_BG, dt_film_import1_create(film)); return filmid; } diff --git a/src/common/mipmap_cache.c b/src/common/mipmap_cache.c index c98942a76306..4612b2db47e6 100644 --- a/src/common/mipmap_cache.c +++ b/src/common/mipmap_cache.c @@ -891,7 +891,7 @@ void dt_mipmap_cache_get_with_caller( // and opposite: prefetch without locking if(mip > DT_MIPMAP_FULL || (int)mip < DT_MIPMAP_0) return; // remove the (int) once we no longer have to support gcc < 4.8 :/ - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_FG, dt_image_load_job_create(imgid, mip)); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_FG, dt_image_load_job_create(imgid, mip)); } else if(flags == DT_MIPMAP_PREFETCH_DISK) { @@ -903,7 +903,7 @@ void dt_mipmap_cache_get_with_caller( snprintf(filename, sizeof(filename), "%s.d/%d/%"PRIu32".jpg", cache->cachedir, (int)mip, key); // don't attempt to load if disk cache doesn't exist if(!g_file_test(filename, G_FILE_TEST_EXISTS)) return; - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_FG, dt_image_load_job_create(imgid, mip)); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_FG, dt_image_load_job_create(imgid, mip)); } else if(flags == DT_MIPMAP_BLOCKING) { diff --git a/src/control/control.c b/src/control/control.c index 755dbd124669..718e8e8a5c0e 100644 --- a/src/control/control.c +++ b/src/control/control.c @@ -110,8 +110,13 @@ const dt_action_def_t dt_action_def_modifiers _action_elements_modifiers, NULL, TRUE }; -void dt_control_init(dt_control_t *s) +void dt_control_init(const gboolean withgui) { + dt_control_t *s = darktable.control = calloc(1, sizeof(dt_control_t)); + dt_atomic_set_int(&s->running, DT_CONTROL_STATE_DISABLED); + + if(!withgui) return; + s->actions_global = (dt_action_t){ DT_ACTION_TYPE_GLOBAL, "global", C_("accel", "global"), @@ -200,8 +205,8 @@ void dt_control_init(dt_control_t *s) s->confirm_mapping = TRUE; s->widget_definitions = g_ptr_array_new (); s->input_drivers = NULL; - dt_atomic_set_int(&s->running, DT_CONTROL_STATE_DISABLED); dt_atomic_set_int(&s->quitting, 0); + dt_atomic_set_int(&s->pending_jobs, 0); s->cups_started = FALSE; dt_action_define_fallback(DT_ACTION_TYPE_IOP, &dt_action_def_iop); @@ -241,7 +246,7 @@ void dt_control_init(dt_control_t *s) dt_pthread_mutex_init(&s->progress_system.mutex, NULL); // start threads - dt_control_jobs_init(s); + dt_control_jobs_init(); s->button_down = 0; s->button_down_which = 0; @@ -289,9 +294,7 @@ void dt_control_change_cursor(dt_cursor_t curs) gboolean dt_control_running() { - dt_control_t *dc = darktable.control; - const int status = dc ? dt_atomic_get_int(&dc->running) : DT_CONTROL_STATE_DISABLED; - return status == DT_CONTROL_STATE_RUNNING; + return dt_atomic_get_int(&darktable.control->running) == DT_CONTROL_STATE_RUNNING; } void dt_control_quit() @@ -323,11 +326,9 @@ void dt_control_quit() } } -void dt_control_shutdown(dt_control_t *s) +void dt_control_shutdown() { - if(!s) - return; - + dt_control_t *s = darktable.control; dt_pthread_mutex_lock(&s->cond_mutex); const gboolean cleanup = dt_atomic_exch_int(&s->running, DT_CONTROL_STATE_DISABLED) == DT_CONTROL_STATE_CLEANUP; pthread_cond_broadcast(&s->cond); @@ -361,23 +362,27 @@ void dt_control_shutdown(dt_control_t *s) } } -void dt_control_cleanup(dt_control_t *s) +void dt_control_cleanup(const gboolean withgui) { - if(!s) - return; - // vacuum TODO: optional? - // DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "PRAGMA incremental_vacuum(0)", NULL, NULL, NULL); - // DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "vacuum", NULL, NULL, NULL); - dt_control_jobs_cleanup(s); - dt_pthread_mutex_destroy(&s->queue_mutex); - dt_pthread_mutex_destroy(&s->cond_mutex); - dt_pthread_mutex_destroy(&s->log_mutex); - dt_pthread_mutex_destroy(&s->toast_mutex); - dt_pthread_mutex_destroy(&s->res_mutex); - dt_pthread_mutex_destroy(&s->progress_system.mutex); - if(s->widgets) g_hash_table_destroy(s->widgets); - if(s->shortcuts) g_sequence_free(s->shortcuts); - if(s->input_drivers) g_slist_free_full(s->input_drivers, g_free); + dt_control_t *s = darktable.control; + if(withgui) + { + // vacuum TODO: optional? + // DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "PRAGMA incremental_vacuum(0)", NULL, NULL, NULL); + // DT_DEBUG_SQLITE3_EXEC(dt_database_get(darktable.db), "vacuum", NULL, NULL, NULL); + dt_control_jobs_cleanup(); + dt_pthread_mutex_destroy(&s->queue_mutex); + dt_pthread_mutex_destroy(&s->cond_mutex); + dt_pthread_mutex_destroy(&s->log_mutex); + dt_pthread_mutex_destroy(&s->toast_mutex); + dt_pthread_mutex_destroy(&s->res_mutex); + dt_pthread_mutex_destroy(&s->progress_system.mutex); + if(s->widgets) g_hash_table_destroy(s->widgets); + if(s->shortcuts) g_sequence_free(s->shortcuts); + if(s->input_drivers) g_slist_free_full(s->input_drivers, g_free); + } + free(s); + darktable.control = NULL; } @@ -641,6 +646,7 @@ static gboolean _redraw_center(gpointer user_data) void dt_control_log(const char *msg, ...) { + if(!dt_control_running()) return; dt_control_t *dc = darktable.control; dt_pthread_mutex_lock(&dc->log_mutex); va_list ap; @@ -698,6 +704,7 @@ static void _toast_log(const gboolean markup, const char *msg, va_list ap) void dt_toast_log(const char *msg, ...) { + if(!dt_control_running()) return; va_list ap; va_start(ap, msg); _toast_log(FALSE, msg, ap); @@ -706,6 +713,7 @@ void dt_toast_log(const char *msg, ...) void dt_toast_markup_log(const char *msg, ...) { + if(!dt_control_running()) return; va_list ap; va_start(ap, msg); _toast_log(TRUE, msg, ap); @@ -723,6 +731,7 @@ static void _control_log_ack_all() void dt_control_log_busy_enter() { + if(!dt_control_running()) return; dt_control_t *dc = darktable.control; dt_pthread_mutex_lock(&dc->log_mutex); dc->log_busy++; @@ -731,6 +740,7 @@ void dt_control_log_busy_enter() void dt_control_toast_busy_enter() { + if(!dt_control_running()) return; dt_control_t *dc = darktable.control; dt_pthread_mutex_lock(&dc->toast_mutex); dc->toast_busy++; @@ -739,6 +749,7 @@ void dt_control_toast_busy_enter() void dt_control_log_busy_leave() { + if(!dt_control_running()) return; dt_control_t *dc = darktable.control; dt_pthread_mutex_lock(&dc->log_mutex); dc->log_busy--; @@ -749,6 +760,7 @@ void dt_control_log_busy_leave() void dt_control_toast_busy_leave() { + if(!dt_control_running()) return; dt_control_t *dc = darktable.control; dt_pthread_mutex_lock(&dc->toast_mutex); dc->toast_busy--; @@ -798,8 +810,9 @@ void dt_control_queue_redraw_widget(GtkWidget *widget) } } -int dt_control_key_pressed_override(guint key, guint state) +gboolean dt_control_key_pressed_override(guint key, guint state) { + if(!dt_control_running()) return FALSE; // TODO: if darkroom mode // did a : vim-style command start? static GList *autocomplete = NULL; @@ -890,7 +903,7 @@ int dt_control_key_pressed_override(guint key, guint state) { // TODO: step history down and copy to vimkey } - return 1; + return TRUE; } else if(key == ':') { @@ -898,15 +911,16 @@ int dt_control_key_pressed_override(guint key, guint state) dc->vimkey[1] = 0; dc->vimkey_cnt = 1; dt_control_log("%s", dc->vimkey); - return 1; + return TRUE; } - return 0; + return FALSE; } -void dt_control_hinter_message(const dt_control_t *s, const char *message) +void dt_control_hinter_message(const char *message) { - if(s->proxy.hinter.module) + dt_control_t *s = darktable.control; + if(s && s->proxy.hinter.module) return s->proxy.hinter.set_message(s->proxy.hinter.module, message); } diff --git a/src/control/control.h b/src/control/control.h index 54d308cfcc22..24b0972f8a49 100644 --- a/src/control/control.h +++ b/src/control/control.h @@ -51,38 +51,38 @@ gboolean dt_control_draw_endmarker(GtkWidget *widget, cairo_t *crf, gpointer use void dt_control_button_pressed(double x, double y, double pressure, int which, int type, uint32_t state); void dt_control_button_released(double x, double y, int which, uint32_t state); void dt_control_mouse_moved(double x, double y, double pressure, int which); -void dt_control_mouse_leave(); -void dt_control_mouse_enter(); -int dt_control_key_pressed_override(guint key, guint state); +void dt_control_mouse_leave(void); +void dt_control_mouse_enter(void); +gboolean dt_control_key_pressed_override(guint key, guint state); gboolean dt_control_configure(GtkWidget *da, GdkEventConfigure *event, gpointer user_data); void dt_control_log(const char *msg, ...) __attribute__((format(printf, 1, 2))); void dt_toast_log(const char *msg, ...) __attribute__((format(printf, 1, 2))); void dt_toast_markup_log(const char *msg, ...) __attribute__((format(printf, 1, 2))); -void dt_control_log_busy_enter(); -void dt_control_toast_busy_enter(); -void dt_control_log_busy_leave(); -void dt_control_toast_busy_leave(); +void dt_control_log_busy_enter(void); +void dt_control_toast_busy_enter(void); +void dt_control_log_busy_leave(void); +void dt_control_toast_busy_leave(void); void dt_control_draw_busy_msg(cairo_t *cr, int width, int height); // disable the possibility to change the cursor shape with dt_control_change_cursor -void dt_control_forbid_change_cursor(); +void dt_control_forbid_change_cursor(void); // enable the possibility to change the cursor shape with dt_control_change_cursor -void dt_control_allow_change_cursor(); +void dt_control_allow_change_cursor(void); void dt_control_change_cursor(dt_cursor_t cursor); -void dt_control_write_sidecar_files(); -void dt_control_delete_images(); +void dt_control_write_sidecar_files(void); +void dt_control_delete_images(void); /** \brief request redraw of the workspace. This redraws the whole workspace within a gdk critical section to prevent several threads to carry out a redraw which will end up in crashes. */ -void dt_control_queue_redraw(); +void dt_control_queue_redraw(void); /** \brief request redraw of center window. This redraws the center view within a gdk critical section to prevent several threads to carry out the redraw. */ -void dt_control_queue_redraw_center(); +void dt_control_queue_redraw_center(void); /** \brief threadsafe request of redraw of specific widget. Use this function if you need to redraw a specific widget @@ -93,26 +93,26 @@ void dt_control_queue_redraw_widget(GtkWidget *widget); /** \brief request redraw of the navigation widget. This redraws the wiget of the navigation module. */ -void dt_control_navigation_redraw(); +void dt_control_navigation_redraw(void); /** \brief request redraw of the log widget. This redraws the message label. */ -void dt_control_log_redraw(); +void dt_control_log_redraw(void); /** \brief request redraw of the toast widget. This redraws the message label. */ -void dt_control_toast_redraw(); +void dt_control_toast_redraw(void); -void dt_ctl_switch_mode(); +void dt_ctl_switch_mode(void); void dt_ctl_switch_mode_to(const char *mode); void dt_ctl_switch_mode_to_by_view(const dt_view_t *view); struct dt_control_t; /** sets the hinter message */ -void dt_control_hinter_message(const struct dt_control_t *s, const char *message); +void dt_control_hinter_message(const char *message); #define DT_CTL_LOG_SIZE 8 // must be power-of-2 #define DT_CTL_TOAST_SIZE 2 @@ -188,6 +188,7 @@ typedef struct dt_control_t // job management dt_atomic_int running; dt_atomic_int quitting; + dt_atomic_int pending_jobs; gboolean cups_started; gboolean export_scheduled; dt_pthread_mutex_t queue_mutex, cond_mutex; @@ -245,21 +246,21 @@ typedef struct dt_control_t } dt_control_t; -void dt_control_init(dt_control_t *s); +void dt_control_init(gboolean withgui); // join all worker threads. -void dt_control_shutdown(dt_control_t *s); -void dt_control_cleanup(dt_control_t *s); +void dt_control_shutdown(void); +void dt_control_cleanup(const gboolean withgui); // call this to quit dt -void dt_control_quit(); +void dt_control_quit(void); /** get threadsafe running state. */ -gboolean dt_control_running(); +gboolean dt_control_running(void); // thread-safe interface between core and gui. // is the locking really needed? -dt_imgid_t dt_control_get_mouse_over_id(); +dt_imgid_t dt_control_get_mouse_over_id(void); void dt_control_set_mouse_over_id(const dt_imgid_t value); G_END_DECLS diff --git a/src/control/jobs.c b/src/control/jobs.c index b7b8f054e307..8d07be190579 100644 --- a/src/control/jobs.c +++ b/src/control/jobs.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2009-2024 darktable developers. + Copyright (C) 2009-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -84,7 +84,7 @@ static void _control_job_set_state(_dt_job_t *job, dt_pthread_mutex_lock(&job->state_mutex); if(state >= DT_JOB_STATE_FINISHED && job->state != DT_JOB_STATE_RUNNING && job->progress) { - dt_control_progress_destroy(darktable.control, job->progress); + dt_control_progress_destroy(job->progress); job->progress = NULL; } job->state = state; @@ -152,24 +152,19 @@ dt_job_t *dt_control_job_create(dt_job_execute_callback execute, dt_view_type_flags_t dt_control_job_get_view_creator(const dt_job_t *job) { - return job->view_creator; + return job && job->view_creator; } gboolean dt_control_job_is_synchronous(const dt_job_t *job) { - return job->is_synchronous; -} - -void dt_control_job_set_synchronous(dt_job_t *job, gboolean sync) -{ - job->is_synchronous = sync; + return job && job->is_synchronous; } void dt_control_job_dispose(_dt_job_t *job) { if(!job) return; if(job->progress) - dt_control_progress_destroy(darktable.control, job->progress); + dt_control_progress_destroy(job->progress); job->progress = NULL; _control_job_set_state(job, DT_JOB_STATE_DISPOSED); if(job->params_destroy) @@ -179,53 +174,43 @@ void dt_control_job_dispose(_dt_job_t *job) free(job); } -void dt_control_job_set_state_callback(_dt_job_t *job, dt_job_state_change_callback cb) +static inline const char *_queuename(const dt_job_queue_t id) { - // once the job got added to the queue it may not be changed from the outside - if(dt_control_job_get_state(job) != DT_JOB_STATE_INITIALIZED) - return; // get_state returns DISPOSED when job == NULL - job->state_changed_cb = cb; + switch(id) + { + case DT_JOB_QUEUE_USER_FG: return "DT_JOB_QUEUE_USER_FG"; + case DT_JOB_QUEUE_SYSTEM_FG: return "DT_JOB_QUEUE_SYSTEM_FG"; + case DT_JOB_QUEUE_USER_BG: return "DT_JOB_QUEUE_USER_BG"; + case DT_JOB_QUEUE_USER_EXPORT: return "DT_JOB_QUEUE_USER_EXPORT"; + case DT_JOB_QUEUE_SYSTEM_BG: return "DT_JOB_QUEUE_SYSTEM_BG"; + case DT_JOB_QUEUE_SYNCHRONOUS: return "DT_JOB_QUEUE_SYNCHRONOUS"; + default: return "???"; + } } - // We don't want to log dt_get_wtime() as we already show the stamp static void _control_job_print(_dt_job_t *job, const char *info, const char *err, int32_t res) { if(!job) return; - dt_print(DT_DEBUG_CONTROL, "[%s]\t%02d %s %s | queue: %d | priority: %d", - info, res, err, job->description, job->queue, job->priority); + dt_print(DT_DEBUG_CONTROL, "[%s]\t%02d %s %s | queue: %s | priority: %d", + info, res, err, job->description, _queuename(job->queue), job->priority); } -void dt_control_job_cancel(_dt_job_t *job) + +static __thread int32_t threadid = -1; +// As threadid is `per thread` we don't have to use atomics +static inline int32_t _control_get_threadid() { - _control_job_set_state(job, DT_JOB_STATE_CANCELLED); + return threadid > -1 ? threadid : darktable.control->num_threads; } -void dt_control_job_wait(_dt_job_t *job) +static inline int32_t _control_get_threadid_res() { - if(!job) return; - dt_job_state_t state = dt_control_job_get_state(job); - - // NOTE: could also use signals. - - // if the job is merely queued and hasn't started yet, we - // need to wait until it is actually started before attempting - // to grab the mutex, or it will always succeed immediately - while(state == DT_JOB_STATE_QUEUED) - { - g_usleep(100000); // wait 0.1 seconds - state = dt_control_job_get_state(job); - } + return threadid > -1 ? threadid : DT_CTL_WORKER_RESERVED; +} - /* if job execution is not finished let's wait for it */ - if(state == DT_JOB_STATE_RUNNING || state == DT_JOB_STATE_CANCELLED) - { - // once the job finishes, it unlocks the mutex - // so by locking the mutex here, we will only get the lock once the job - // has finished and unlocked it. - dt_pthread_mutex_lock(&job->wait_mutex); - // yay, the job finished, we got the lock. nothing more to do. - dt_pthread_mutex_unlock(&job->wait_mutex); - } +void dt_control_job_cancel(_dt_job_t *job) +{ + _control_job_set_state(job, DT_JOB_STATE_CANCELLED); } static gboolean _control_run_job_res(dt_control_t *control, int32_t res) @@ -312,7 +297,7 @@ static _dt_job_t *_control_schedule_job(dt_control_t *control) if(winner_queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = TRUE; // and place it in scheduled job array (for job deduping) - control->job[dt_control_get_threadid()] = job; + control->job[_control_get_threadid()] = job; // increment the priorities of the others for(int i = 0; i < DT_JOB_QUEUE_MAX; i++) @@ -328,7 +313,7 @@ static _dt_job_t *_control_schedule_job(dt_control_t *control) static void _control_job_execute(_dt_job_t *job) { - _control_job_print(job, "run_job+", "", DT_CTL_WORKER_RESERVED + dt_control_get_threadid()); + _control_job_print(job, "run_job+", "", DT_CTL_WORKER_RESERVED + _control_get_threadid()); _control_job_set_state(job, DT_JOB_STATE_RUNNING); @@ -336,7 +321,7 @@ static void _control_job_execute(_dt_job_t *job) job->result = job->execute(job); _control_job_set_state(job, DT_JOB_STATE_FINISHED); - _control_job_print(job, "run_job-", "", DT_CTL_WORKER_RESERVED + dt_control_get_threadid()); + _control_job_print(job, "run_job-", "", DT_CTL_WORKER_RESERVED + _control_get_threadid()); } static gboolean _control_run_job(dt_control_t *control) @@ -354,21 +339,20 @@ static gboolean _control_run_job(dt_control_t *control) // remove the job from scheduled job array (for job deduping) dt_pthread_mutex_lock(&control->queue_mutex); - control->job[dt_control_get_threadid()] = NULL; + control->job[_control_get_threadid()] = NULL; if(job->queue == DT_JOB_QUEUE_USER_EXPORT) control->export_scheduled = FALSE; dt_pthread_mutex_unlock(&control->queue_mutex); // and free it dt_control_job_dispose(job); + dt_atomic_sub_int(&control->pending_jobs, 1); return FALSE; } -gboolean dt_control_add_job_res(dt_control_t *control, - _dt_job_t *job, - int32_t res) +gboolean dt_control_add_job_res(_dt_job_t *job, const int32_t res) { - if(!control) return TRUE; + dt_control_t *control = darktable.control; if(((unsigned int)res) >= DT_CTL_WORKER_RESERVED || !job) { dt_control_job_dispose(job); @@ -400,11 +384,9 @@ gboolean dt_control_add_job_res(dt_control_t *control, return FALSE; } -gboolean dt_control_add_job(dt_control_t *control, - dt_job_queue_t queue_id, - _dt_job_t *job) +gboolean dt_control_add_job(dt_job_queue_t queue_id, _dt_job_t *job) { - if(!control) return TRUE; + dt_control_t *control = darktable.control; if((((unsigned int)queue_id) >= DT_JOB_QUEUE_MAX && queue_id != DT_JOB_QUEUE_SYNCHRONOUS) || !job) { dt_control_job_dispose(job); @@ -415,7 +397,7 @@ gboolean dt_control_add_job(dt_control_t *control, { // whatever we are adding here won't be scheduled as the system isn't running. execute it synchronous instead. dt_pthread_mutex_lock(&job->wait_mutex); // is that even needed? - dt_control_job_set_synchronous(job, TRUE); + job->is_synchronous = TRUE; _control_job_execute(job); dt_pthread_mutex_unlock(&job->wait_mutex); @@ -434,6 +416,7 @@ gboolean dt_control_add_job(dt_control_t *control, _control_job_print(job, "add_job", "", (int32_t)length); + dt_atomic_add_int(&control->pending_jobs, 1); if(queue_id == DT_JOB_QUEUE_SYSTEM_FG) { // this is a stack with limited size and bubble up and all that stuff @@ -442,7 +425,7 @@ gboolean dt_control_add_job(dt_control_t *control, // check if we have already scheduled the job for(int k = 0; k < control->num_threads; k++) { - _dt_job_t *other_job = (_dt_job_t *)control->job[k]; + _dt_job_t *other_job = control->job[k]; if(_control_job_equal(job, other_job)) { _control_job_print(other_job, "add_job", "found job already in scheduled:", -1); @@ -451,6 +434,7 @@ gboolean dt_control_add_job(dt_control_t *control, _control_job_set_state(job, DT_JOB_STATE_DISCARDED); dt_control_job_dispose(job); + dt_atomic_sub_int(&control->pending_jobs, 1); return 0; // there can't be any further copy } @@ -459,13 +443,14 @@ gboolean dt_control_add_job(dt_control_t *control, // if the job is already in the queue -> move it to the top for(GList *iter = *queue; iter; iter = g_list_next(iter)) { - _dt_job_t *other_job = (_dt_job_t *)iter->data; + _dt_job_t *other_job = iter->data; if(_control_job_equal(job, other_job)) { _control_job_print(other_job, "add_job", "found job already in queue", -1); *queue = g_list_delete_link(*queue, iter); length--; + dt_atomic_sub_int(&control->pending_jobs, 1); job_for_disposal = job; @@ -482,10 +467,11 @@ gboolean dt_control_add_job(dt_control_t *control, if(length > DT_CONTROL_MAX_JOBS) { GList *last = g_list_last(*queue); - _control_job_set_state((_dt_job_t *)last->data, DT_JOB_STATE_DISCARDED); - dt_control_job_dispose((_dt_job_t *)last->data); + _control_job_set_state(last->data, DT_JOB_STATE_DISCARDED); + dt_control_job_dispose(last->data); *queue = g_list_delete_link(*queue, last); length--; + dt_atomic_sub_int(&control->pending_jobs, 1); } control->queue_length[queue_id] = length; @@ -517,20 +503,6 @@ gboolean dt_control_add_job(dt_control_t *control, return FALSE; } -static __thread int threadid = -1; - -int32_t dt_control_get_threadid() -{ - if(threadid > -1) return threadid; - return darktable.control->num_threads; -} - -static inline int32_t _control_get_threadid_res() -{ - if(threadid > -1) return threadid; - return DT_CTL_WORKER_RESERVED; -} - static void *_control_work_res(void *ptr) { #ifdef _OPENMP // need to do this in every thread @@ -543,7 +515,7 @@ static void *_control_work_res(void *ptr) snprintf(name, sizeof(name), "worker res %d", threadid); dt_pthread_setname(name); free(params); - int32_t threadid_res = _control_get_threadid_res(); + const int32_t threadid_res = _control_get_threadid_res(); while(dt_control_running()) { // dt_print(DT_DEBUG_CONTROL, "[control_work] %d", threadid_res); @@ -588,10 +560,9 @@ static void *_control_work(void *ptr) snprintf(name, sizeof(name), "worker %d", threadid); dt_pthread_setname(name); free(params); - // int32_t threadid = dt_control_get_threadid(); + while(dt_control_running()) { - // dt_print(DT_DEBUG_CONTROL, "[control_work] %d", threadid); if(_control_run_job(control)) { // wait for a new job. @@ -605,27 +576,27 @@ static void *_control_work(void *ptr) // convenience functions to have a progress bar for the job. // this allows to show the gui indicator of the job even before it got scheduled -void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable) +void dt_control_job_add_progress(dt_job_t *job, const char *message, const gboolean cancellable) { if(!job) return; - job->progress = dt_control_progress_create(darktable.control, TRUE, message); + job->progress = dt_control_progress_create(TRUE, message); if(cancellable) - dt_control_progress_attach_job(darktable.control, job->progress, job); + dt_control_progress_attach_job(job->progress, job); } void dt_control_job_set_progress_message(dt_job_t *job, const char *message) { if(!job || !job->progress) return; - dt_control_progress_set_message(darktable.control, job->progress, message); + dt_control_progress_set_message(job->progress, message); } -void dt_control_job_set_progress(dt_job_t *job, double value) +void dt_control_job_set_progress(dt_job_t *job, const double value) { if(!job || !job->progress) return; - dt_control_progress_set_progress(darktable.control, job->progress, value); + dt_control_progress_set_progress(job->progress, value); } -double dt_control_job_get_progress(dt_job_t *job) +double dt_control_job_get_progress(const dt_job_t *job) { if(!job || !job->progress) return -1.0; return dt_control_progress_get_progress(job->progress); @@ -633,8 +604,9 @@ double dt_control_job_get_progress(dt_job_t *job) // moved out of control.c to be able to make some helper functions static -void dt_control_jobs_init(dt_control_t *control) +void dt_control_jobs_init() { + dt_control_t *control = darktable.control; // start threads control->num_threads = dt_worker_threads(); control->thread = (pthread_t *)calloc(control->num_threads, sizeof(pthread_t)); @@ -672,14 +644,28 @@ void dt_control_jobs_init(dt_control_t *control) dt_print(DT_DEBUG_ALWAYS, "[dt_control_jobs_init] couldn't create all threads, problems ahead"); } -void dt_control_jobs_cleanup(dt_control_t *control) +void dt_control_jobs_cleanup() { + dt_control_t *control = darktable.control; free(control->job); control->job = NULL; free(control->thread); control->thread = NULL; } +int dt_control_jobs_pending() +{ + dt_control_t *control = darktable.control; + if(!control) return 0; + + int pending = dt_atomic_get_int(&control->pending_jobs); + if(darktable.backthumbs.running) + pending--; +#ifdef HAVE_PRINT + pending--; +#endif + return pending; +} // clang-format off // modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py // vim: shiftwidth=2 expandtab tabstop=2 cindent diff --git a/src/control/jobs.h b/src/control/jobs.h index ffbd0a24373a..78faac814482 100644 --- a/src/control/jobs.h +++ b/src/control/jobs.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2009-2024 darktable developers. + Copyright (C) 2009-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -62,13 +62,9 @@ typedef void (*dt_job_destroy_callback)(void *data); dt_job_t *dt_control_job_create(dt_job_execute_callback execute, const char *msg, ...) __attribute__((format(printf, 2, 3))); /** destroy a job object and free its memory. this does NOT remove it from any job queues! */ void dt_control_job_dispose(dt_job_t *job); -/** setup a state callback for job. */ -void dt_control_job_set_state_callback(dt_job_t *job, dt_job_state_change_callback cb); /** cancel a job, running or in queue. */ void dt_control_job_cancel(dt_job_t *job); dt_job_state_t dt_control_job_get_state(dt_job_t *job); -/** wait for a job to finish execution. */ -void dt_control_job_wait(dt_job_t *job); /** set job params and a callback to destroy those params */ void dt_control_job_set_params(dt_job_t *job, void *params, dt_job_destroy_callback callback); /** set job params (with size params_size) and a callback to destroy those params. @@ -78,23 +74,20 @@ void dt_control_job_set_params_with_size(dt_job_t *job, void *params, size_t par /** get job params. WARNING: you must not free them. dt_control_job_dispose() will take care of that */ void *dt_control_job_get_params(const dt_job_t *job); -void dt_control_job_add_progress(dt_job_t *job, const char *message, gboolean cancellable); +void dt_control_job_add_progress(dt_job_t *job, const char *message, const gboolean cancellable); void dt_control_job_set_progress_message(dt_job_t *job, const char *message); -void dt_control_job_set_progress(dt_job_t *job, double value); -double dt_control_job_get_progress(dt_job_t *job); +void dt_control_job_set_progress(dt_job_t *job, const double value); +double dt_control_job_get_progress(const dt_job_t *job); -struct dt_control_t; -void dt_control_jobs_init(struct dt_control_t *control); -void dt_control_jobs_cleanup(struct dt_control_t *control); +void dt_control_jobs_init(void); +void dt_control_jobs_cleanup(void); +int dt_control_jobs_pending(void); -gboolean dt_control_add_job(struct dt_control_t *control, dt_job_queue_t queue_id, dt_job_t *job); -gboolean dt_control_add_job_res(struct dt_control_t *s, dt_job_t *job, int32_t res); +gboolean dt_control_add_job(dt_job_queue_t queue_id, dt_job_t *job); +gboolean dt_control_add_job_res(dt_job_t *job, const int32_t res); dt_view_type_flags_t dt_control_job_get_view_creator(const dt_job_t *job); gboolean dt_control_job_is_synchronous(const dt_job_t *job); -void dt_control_job_set_synchronous(dt_job_t *job, gboolean sync); - -int32_t dt_control_get_threadid(); #ifdef HAVE_GPHOTO2 #include "control/jobs/camera_jobs.h" diff --git a/src/control/jobs/control_jobs.c b/src/control/jobs/control_jobs.c index b6e513146ea8..e7319d368a66 100644 --- a/src/control/jobs/control_jobs.c +++ b/src/control/jobs/control_jobs.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2010-2024 darktable developers. + Copyright (C) 2010-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -139,7 +139,7 @@ static void _update_progress(dt_job_t *job, double fraction, double *prev_time) } /* enumerator of images from filmroll */ -static void dt_control_image_enumerator_job_film_init(dt_control_image_enumerator_t *t, +static void _control_image_enumerator_job_film_init(dt_control_image_enumerator_t *t, const int32_t filmid) { sqlite3_stmt *stmt; @@ -230,7 +230,7 @@ static int32_t _generic_dt_control_fileop_images_job_run return 0; } -static void *dt_control_image_enumerator_alloc() +static void *_control_image_enumerator_alloc() { dt_control_image_enumerator_t *params = calloc(1, sizeof(dt_control_image_enumerator_t)); if(!params) return NULL; @@ -243,7 +243,7 @@ gboolean _cursor_clear_busy(gpointer user_data) return G_SOURCE_REMOVE; } -static void dt_control_image_enumerator_cleanup(void *p) +static void _control_image_enumerator_cleanup(void *p) { dt_control_image_enumerator_t *params = p; @@ -261,7 +261,7 @@ static void dt_control_image_enumerator_cleanup(void *p) typedef enum {PROGRESS_NONE, PROGRESS_SIMPLE, PROGRESS_CANCELLABLE, PROGRESS_BLOCKING} progress_type_t; -static dt_job_t *dt_control_generic_images_job_create(dt_job_execute_callback execute, +static dt_job_t *_control_generic_images_job_create(dt_job_execute_callback execute, const char *message, const int flag, gpointer data, @@ -270,7 +270,7 @@ static dt_job_t *dt_control_generic_images_job_create(dt_job_execute_callback ex { dt_job_t *job = dt_control_job_create(execute, "%s", message); if(!job) return NULL; - dt_control_image_enumerator_t *params = dt_control_image_enumerator_alloc(); + dt_control_image_enumerator_t *params = _control_image_enumerator_alloc(); if(!params) { dt_control_job_dispose(job); @@ -288,14 +288,14 @@ static dt_job_t *dt_control_generic_images_job_create(dt_job_execute_callback ex dt_control_job_add_progress(job, _(message), progress_type == PROGRESS_CANCELLABLE); params->index = dt_act_on_get_images(only_visible, TRUE, FALSE); - dt_control_job_set_params(job, params, dt_control_image_enumerator_cleanup); + dt_control_job_set_params(job, params, _control_image_enumerator_cleanup); params->flag = flag; params->data = data; return job; } -static dt_job_t *dt_control_generic_image_job_create(dt_job_execute_callback execute, +static dt_job_t *_control_generic_image_job_create(dt_job_execute_callback execute, const char *message, const int flag, gpointer data, @@ -305,7 +305,7 @@ static dt_job_t *dt_control_generic_image_job_create(dt_job_execute_callback exe dt_job_t *job = dt_control_job_create(execute, "%s", message); if(!job) return NULL; - dt_control_image_enumerator_t *params = dt_control_image_enumerator_alloc(); + dt_control_image_enumerator_t *params = _control_image_enumerator_alloc(); if(!params) { dt_control_job_dispose(job); @@ -316,14 +316,14 @@ static dt_job_t *dt_control_generic_image_job_create(dt_job_execute_callback exe params->index = g_list_append(NULL, GINT_TO_POINTER(imgid)); - dt_control_job_set_params(job, params, dt_control_image_enumerator_cleanup); + dt_control_job_set_params(job, params, _control_image_enumerator_cleanup); params->flag = flag; params->data = data; return job; } -static int32_t dt_control_write_sidecar_files_job_run(dt_job_t *job) +static int32_t _control_write_sidecar_files_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); char message[512] = { 0 }; @@ -397,22 +397,22 @@ typedef struct dt_control_merge_hdr_format_t dt_control_merge_hdr_t *d; } dt_control_merge_hdr_format_t; -static int dt_control_merge_hdr_bpp(dt_imageio_module_data_t *data) +static int _control_merge_hdr_bpp(dt_imageio_module_data_t *data) { return 32; } -static int dt_control_merge_hdr_levels(dt_imageio_module_data_t *data) +static int _control_merge_hdr_levels(dt_imageio_module_data_t *data) { return IMAGEIO_RGB | IMAGEIO_FLOAT; } -static const char *dt_control_merge_hdr_mime(dt_imageio_module_data_t *data) +static const char *_control_merge_hdr_mime(dt_imageio_module_data_t *data) { return "memory"; } -static float envelope(const float xx) +static float _envelope(const float xx) { const float x = CLAMPS(xx, 0.0f, 1.0f); // const float alpha = 2.0f; @@ -432,7 +432,7 @@ static float envelope(const float xx) } } -static int dt_control_merge_hdr_process(dt_imageio_module_data_t *datai, +static int _control_merge_hdr_process(dt_imageio_module_data_t *datai, const char *filename, const void *const ivoid, dt_colorspaces_color_profile_type_t over_type, @@ -563,7 +563,7 @@ static int dt_control_merge_hdr_process(dt_imageio_module_data_t *datai, // clipped somewhere, the other channels might still prove // useful. we'll check for individual channel saturation // below. - w *= d->epsw + envelope((M + offset) / saturation); + w *= d->epsw + _envelope((M + offset) / saturation); } if(M + offset >= saturation) @@ -598,7 +598,7 @@ static int dt_control_merge_hdr_process(dt_imageio_module_data_t *datai, return 0; } -static int32_t dt_control_merge_hdr_job_run(dt_job_t *job) +static int32_t _control_merge_hdr_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -613,10 +613,10 @@ static int32_t dt_control_merge_hdr_job_run(dt_job_t *job) dt_control_merge_hdr_t d = (dt_control_merge_hdr_t){.epsw = 1e-8f, .abort = FALSE }; dt_imageio_module_format_t buf = (dt_imageio_module_format_t) - {.mime = dt_control_merge_hdr_mime, - .levels = dt_control_merge_hdr_levels, - .bpp = dt_control_merge_hdr_bpp, - .write_image = dt_control_merge_hdr_process }; + {.mime = _control_merge_hdr_mime, + .levels = _control_merge_hdr_levels, + .bpp = _control_merge_hdr_bpp, + .write_image = _control_merge_hdr_process }; dt_control_merge_hdr_format_t dat = (dt_control_merge_hdr_format_t){.parent = { 0 }, .d = &d }; @@ -702,7 +702,7 @@ static int32_t dt_control_merge_hdr_job_run(dt_job_t *job) return 0; } -static int32_t dt_control_duplicate_images_job_run(dt_job_t *job) +static int32_t _control_duplicate_images_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -746,7 +746,7 @@ static int32_t dt_control_duplicate_images_job_run(dt_job_t *job) return 0; } -static int32_t dt_control_flip_images_job_run(dt_job_t *job) +static int32_t _control_flip_images_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); const int cw = params->flag; @@ -779,7 +779,7 @@ static int32_t dt_control_flip_images_job_run(dt_job_t *job) return 0; } -static int32_t dt_control_monochrome_images_job_run(dt_job_t *job) +static int32_t _control_monochrome_images_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); const int32_t mode = params->flag; @@ -899,7 +899,7 @@ static int32_t _count_images_using_overlay(dt_imgid_t imgid) return exist_count; } -static int32_t dt_control_remove_images_job_run(dt_job_t *job) +static int32_t _control_remove_images_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -1023,7 +1023,7 @@ typedef enum _dt_delete_dialog_choice_t _DT_DELETE_DIALOG_CHOICE_ALL = 1 << 5, } _dt_delete_dialog_choice_t; -static gboolean _dt_delete_dialog_main_thread(gpointer user_data) +static gboolean _delete_dialog_main_thread(gpointer user_data) { _dt_delete_modal_dialog_t* modal_dialog = (_dt_delete_modal_dialog_t*)user_data; dt_pthread_mutex_lock(&modal_dialog->mutex); @@ -1106,7 +1106,7 @@ static gint _dt_delete_file_display_modal_dialog(const int send_to_trash, dt_pthread_mutex_lock(&modal_dialog.mutex); - gdk_threads_add_idle(_dt_delete_dialog_main_thread, &modal_dialog); + gdk_threads_add_idle(_delete_dialog_main_thread, &modal_dialog); while(modal_dialog.dialog_result == GTK_RESPONSE_NONE) dt_pthread_cond_wait(&modal_dialog.cond, &modal_dialog.mutex); @@ -1211,7 +1211,7 @@ static _dt_delete_status_t delete_file_from_disk } -static int32_t dt_control_delete_images_job_run(dt_job_t *job) +static int32_t _control_delete_images_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -1364,7 +1364,7 @@ static int32_t dt_control_delete_images_job_run(dt_job_t *job) return 0; } -static int32_t dt_control_gpx_apply_job_run(dt_job_t *job) +static int32_t _control_gpx_apply_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -1442,21 +1442,21 @@ static int32_t dt_control_gpx_apply_job_run(dt_job_t *job) return 1; } -static int32_t dt_control_move_images_job_run(dt_job_t *job) +static int32_t _control_move_images_job_run(dt_job_t *job) { return _generic_dt_control_fileop_images_job_run(job, &dt_image_move, _("moving %d image"), _("moving %d images")); } -static int32_t dt_control_copy_images_job_run(dt_job_t *job) +static int32_t _control_copy_images_job_run(dt_job_t *job) { return _generic_dt_control_fileop_images_job_run(job, &dt_image_copy, _("copying %d image"), _("copying %d images")); } -static int32_t dt_control_local_copy_images_job_run(dt_job_t *job) +static int32_t _control_local_copy_images_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -1513,7 +1513,7 @@ static int32_t dt_control_local_copy_images_job_run(dt_job_t *job) return 0; } -static int32_t dt_control_refresh_exif_run(dt_job_t *job) +static int32_t _control_refresh_exif_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); GList *t = params->index; @@ -1569,7 +1569,7 @@ static int32_t dt_control_refresh_exif_run(dt_job_t *job) return 0; } -static inline gboolean _safe_history_job_on_imgid(dt_job_t *job, dt_imgid_t imgid) +static inline gboolean _safe_history_job_on_imgid(dt_job_t *job, const dt_imgid_t imgid) { // it is safe to run a history-modifying operation if: // 1. we are running synchronously @@ -1601,6 +1601,7 @@ static int32_t _control_paste_history_job_run(dt_job_t *job) for( ; t && !_job_cancelled(job); t = g_list_next(t)) { const dt_imgid_t imgid = GPOINTER_TO_INT(t->data); + if(!dt_is_valid_imgid(imgid)) continue; // paste the copied history onto the current image, unless it's the one being edited in darkroom if(_safe_history_job_on_imgid(job, imgid)) { @@ -1658,6 +1659,8 @@ static int32_t _control_compress_history_job_run(dt_job_t *job) for( ; t && !_job_cancelled(job); t = g_list_next(t)) { dt_imgid_t imgid = GPOINTER_TO_INT(t->data); + if(!dt_is_valid_imgid(imgid)) continue; + // compress the history of this image, unless it's the one being edited in darkroom if(_safe_history_job_on_imgid(job, imgid)) { @@ -1698,6 +1701,8 @@ static int32_t _control_discard_history_job_run(dt_job_t *job) for( ; t && !_job_cancelled(job); t = g_list_next(t)) { const dt_imgid_t imgid = GPOINTER_TO_INT(t->data); + if(!dt_is_valid_imgid(imgid)) continue; + // discard this image's history, unless it's the one being edited in darkroom if(_safe_history_job_on_imgid(job, imgid)) dt_history_delete(imgid, TRUE); @@ -1743,6 +1748,8 @@ static int32_t _control_apply_styles_job_run(dt_job_t *job) for(GList *t = imgs ; t && !_job_cancelled(job); t = g_list_next(t)) { const dt_imgid_t imgid = GPOINTER_TO_INT(t->data); + if(!dt_is_valid_imgid(imgid)) continue; + dt_undo_lt_history_t *hist = NULL; if(is_overwrite && g_list_is_singleton(styles)) { @@ -1779,16 +1786,14 @@ static int32_t _control_apply_styles_job_run(dt_job_t *job) return 0; } -static int32_t dt_control_export_job_run(dt_job_t *job) +static int32_t _control_export_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); dt_control_export_t *settings = params->data; GList *t = params->index; - dt_imageio_module_format_t *mformat = - dt_imageio_get_format_by_index(settings->format_index); + dt_imageio_module_format_t *mformat = dt_imageio_get_format_by_index(settings->format_index); g_assert(mformat); - dt_imageio_module_storage_t *mstorage = - dt_imageio_get_storage_by_index(settings->storage_index); + dt_imageio_module_storage_t *mstorage = dt_imageio_get_storage_by_index(settings->storage_index); g_assert(mstorage); dt_imageio_module_data_t *sdata = settings->sdata; @@ -1885,8 +1890,7 @@ static int32_t dt_control_export_job_run(dt_job_t *job) dt_control_job_set_progress_message(job, message); // check if image still exists: - const dt_image_t *image = - dt_image_cache_get(darktable.image_cache, (int32_t)imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); if(image) { char imgfilename[PATH_MAX] = { 0 }; @@ -1940,22 +1944,22 @@ static int32_t dt_control_export_job_run(dt_job_t *job) return 0; } -static dt_control_image_enumerator_t *dt_control_gpx_apply_alloc() +static dt_control_image_enumerator_t *_control_gpx_apply_alloc() { - dt_control_image_enumerator_t *params = dt_control_image_enumerator_alloc(); + dt_control_image_enumerator_t *params = _control_image_enumerator_alloc(); if(!params) return NULL; params->data = calloc(1, sizeof(dt_control_gpx_apply_t)); if(!params->data) { - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); return NULL; } return params; } -static void dt_control_gpx_apply_job_cleanup(void *p) +static void _control_gpx_apply_job_cleanup(void *p) { dt_control_image_enumerator_t *params = p; @@ -1966,7 +1970,7 @@ static void dt_control_gpx_apply_job_cleanup(void *p) free(data); - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); } static dt_job_t *_control_gpx_apply_job_create(const gchar *filename, @@ -1974,18 +1978,18 @@ static dt_job_t *_control_gpx_apply_job_create(const gchar *filename, const gchar *tz, GList *imgs) { - dt_job_t *job = dt_control_job_create(&dt_control_gpx_apply_job_run, "gpx apply"); + dt_job_t *job = dt_control_job_create(&_control_gpx_apply_job_run, "gpx apply"); if(!job) return NULL; - dt_control_image_enumerator_t *params = dt_control_gpx_apply_alloc(); + dt_control_image_enumerator_t *params = _control_gpx_apply_alloc(); if(!params) { dt_control_job_dispose(job); return NULL; } - dt_control_job_set_params(job, params, dt_control_gpx_apply_job_cleanup); + dt_control_job_set_params(job, params, _control_gpx_apply_job_cleanup); if(filmid != -1) - dt_control_image_enumerator_job_film_init(params, filmid); + _control_image_enumerator_job_film_init(params, filmid); else if(!imgs) params->index = dt_act_on_get_images(TRUE, TRUE, FALSE); else @@ -1999,27 +2003,24 @@ static dt_job_t *_control_gpx_apply_job_create(const gchar *filename, void dt_control_merge_hdr() { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_merge_hdr_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_merge_hdr_job_run, N_("merge HDR image"), 0, NULL, PROGRESS_CANCELLABLE, TRUE)); } void dt_control_gpx_apply(const gchar *filename, - int32_t filmid, + const int32_t filmid, const gchar *tz, GList *imgs) { - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, - _control_gpx_apply_job_create(filename, filmid, tz, imgs)); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, _control_gpx_apply_job_create(filename, filmid, tz, imgs)); } -void dt_control_duplicate_images(gboolean virgin) +void dt_control_duplicate_images(const gboolean virgin) { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_duplicate_images_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_duplicate_images_job_run, N_("duplicate images"), 0, GINT_TO_POINTER(virgin), PROGRESS_CANCELLABLE, TRUE)); @@ -2027,18 +2028,16 @@ void dt_control_duplicate_images(gboolean virgin) void dt_control_flip_images(const int32_t cw) { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_flip_images_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_flip_images_job_run, N_("flip images"), cw, NULL, PROGRESS_CANCELLABLE, TRUE)); } void dt_control_monochrome_images(const int32_t mode) { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_monochrome_images_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_monochrome_images_job_run, N_("set monochrome images"), mode, NULL, PROGRESS_CANCELLABLE, TRUE)); } @@ -2046,7 +2045,7 @@ void dt_control_monochrome_images(const int32_t mode) gboolean dt_control_remove_images() { // get all selected images now, to avoid the set changing during ui interaction - dt_job_t *job = dt_control_generic_images_job_create(&dt_control_remove_images_job_run, + dt_job_t *job = _control_generic_images_job_create(&_control_remove_images_job_run, N_("remove images"), 0, NULL, PROGRESS_CANCELLABLE, FALSE); if(dt_conf_get_bool("ask_before_remove")) @@ -2069,14 +2068,14 @@ gboolean dt_control_remove_images() return FALSE; } } - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, job); return TRUE; } void dt_control_delete_images() { // first get all selected images, to avoid the set changing during ui interaction - dt_job_t *job = dt_control_generic_images_job_create(&dt_control_delete_images_job_run, + dt_job_t *job = _control_generic_images_job_create(&_control_delete_images_job_run, N_("delete images"), 0, NULL, PROGRESS_SIMPLE, FALSE); const gboolean send_to_trash = dt_conf_get_bool("send_to_trash"); @@ -2104,15 +2103,15 @@ void dt_control_delete_images() return; } } - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, job); } -void dt_control_delete_image(dt_imgid_t imgid) +void dt_control_delete_image(const dt_imgid_t imgid) { // first get all selected images, to avoid the set changing during ui interaction - dt_job_t *job = dt_control_generic_image_job_create(&dt_control_delete_images_job_run, N_("delete images"), 0, + dt_job_t *job = _control_generic_image_job_create(&_control_delete_images_job_run, N_("delete images"), 0, NULL, PROGRESS_SIMPLE, imgid); - int send_to_trash = dt_conf_get_bool("send_to_trash"); + const gboolean send_to_trash = dt_conf_get_bool("send_to_trash"); if(dt_conf_get_bool("ask_before_delete")) { // Do not show the dialog if no valid image @@ -2131,7 +2130,7 @@ void dt_control_delete_image(dt_imgid_t imgid) return; } } - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, job); } void dt_control_move_images() @@ -2140,8 +2139,8 @@ void dt_control_move_images() gchar *dir = NULL; GtkWidget *win = dt_ui_main_window(darktable.gui->ui); - dt_job_t *job = dt_control_generic_images_job_create - (&dt_control_move_images_job_run, N_("move images"), 0, dir, + dt_job_t *job = _control_generic_images_job_create + (&_control_move_images_job_run, N_("move images"), 0, dir, PROGRESS_CANCELLABLE, FALSE); const dt_control_image_enumerator_t *e = dt_control_job_get_params(job); const int number = g_list_length(e->index); @@ -2183,7 +2182,7 @@ void dt_control_move_images() goto abort; } - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, job); return; abort: @@ -2196,8 +2195,8 @@ void dt_control_copy_images() // Open file chooser dialog gchar *dir = NULL; GtkWidget *win = dt_ui_main_window(darktable.gui->ui); - dt_job_t *job = dt_control_generic_images_job_create - (&dt_control_copy_images_job_run, N_("copy images"), 0, dir, + dt_job_t *job = _control_generic_images_job_create + (&_control_copy_images_job_run, N_("copy images"), 0, dir, PROGRESS_CANCELLABLE, FALSE); const dt_control_image_enumerator_t *e = dt_control_job_get_params(job); const int number = g_list_length(e->index); @@ -2240,7 +2239,7 @@ void dt_control_copy_images() goto abort; } - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, job); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, job); return; abort: @@ -2250,9 +2249,8 @@ void dt_control_copy_images() void dt_control_set_local_copy_images() { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_local_copy_images_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_local_copy_images_job_run, N_("local copy images"), 1, NULL, PROGRESS_CANCELLABLE, FALSE)); @@ -2260,9 +2258,8 @@ void dt_control_set_local_copy_images() void dt_control_reset_local_copy_images() { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_local_copy_images_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_local_copy_images_job_run, N_("local copy images"), 0, NULL, PROGRESS_CANCELLABLE, FALSE)); @@ -2270,9 +2267,8 @@ void dt_control_reset_local_copy_images() void dt_control_refresh_exif() { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_refresh_exif_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_refresh_exif_run, N_("refresh EXIF"), 0, NULL, PROGRESS_CANCELLABLE, FALSE)); } @@ -2290,8 +2286,8 @@ static void _add_history_job(GList *imgs, const char *title, dt_job_execute_call imgs = g_list_remove_link(imgs, link); if(styles_data) styles_data->imgs = link; - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYNCHRONOUS, - dt_control_generic_images_job_create(execute, title, 0, + dt_control_add_job(DT_JOB_QUEUE_SYNCHRONOUS, + _control_generic_images_job_create(execute, title, 0, styles_data ? (gpointer)styles_data : (gpointer)link, PROGRESS_BLOCKING, FALSE)); if(styles_data) @@ -2301,8 +2297,8 @@ static void _add_history_job(GList *imgs, const char *title, dt_job_execute_call // but block user interactions other than cancellation if(imgs) { - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(execute, title, 0, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(execute, title, 0, styles_data ? (gpointer)styles_data : (gpointer)imgs, PROGRESS_BLOCKING, FALSE)); } @@ -2361,7 +2357,7 @@ void dt_control_discard_history(GList *imgs) _add_history_job(imgs, N_("discard history"), &_control_discard_history_job_run, NULL); } -void dt_control_apply_styles(GList *imgs, GList *styles, gboolean duplicate) +void dt_control_apply_styles(GList *imgs, GList *styles, const gboolean duplicate) { if(g_list_is_empty(styles) && g_list_is_empty(imgs)) { @@ -2389,22 +2385,22 @@ void dt_control_apply_styles(GList *imgs, GList *styles, gboolean duplicate) } } -static dt_control_image_enumerator_t *dt_control_export_alloc() +static dt_control_image_enumerator_t *_control_export_alloc() { - dt_control_image_enumerator_t *params = dt_control_image_enumerator_alloc(); + dt_control_image_enumerator_t *params = _control_image_enumerator_alloc(); if(!params) return NULL; params->data = calloc(1, sizeof(dt_control_export_t)); if(!params->data) { - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); return NULL; } return params; } -static void dt_control_export_cleanup(void *p) +static void _control_export_cleanup(void *p) { dt_control_image_enumerator_t *params = p; @@ -2419,34 +2415,34 @@ static void dt_control_export_cleanup(void *p) g_free(settings->metadata_export); free(params->data); - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); } void dt_control_export(GList *imgid_list, - int max_width, - int max_height, - int format_index, - int storage_index, - gboolean high_quality, - gboolean upscale, - gboolean dimensions_scale, - gboolean export_masks, + const int max_width, + const int max_height, + const int format_index, + const int storage_index, + const gboolean high_quality, + const gboolean upscale, + const gboolean dimensions_scale, + const gboolean export_masks, char *style, - gboolean style_append, + const gboolean style_append, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, const gchar *metadata_export) { - dt_job_t *job = dt_control_job_create(&dt_control_export_job_run, "export"); + dt_job_t *job = dt_control_job_create(&_control_export_job_run, "export"); if(!job) return; - dt_control_image_enumerator_t *params = dt_control_export_alloc(); + dt_control_image_enumerator_t *params = _control_export_alloc(); if(!params) { dt_control_job_dispose(job); return; } - dt_control_job_set_params(job, params, dt_control_export_cleanup); + dt_control_job_set_params(job, params, _control_export_cleanup); params->index = imgid_list; @@ -2479,7 +2475,7 @@ void dt_control_export(GList *imgid_list, data->metadata_export = g_strdup(metadata_export); dt_control_job_add_progress(job, _("export images"), TRUE); - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_EXPORT, job); + dt_control_add_job(DT_JOB_QUEUE_USER_EXPORT, job); // tell the storage that we got its params for an export so it can // reset itself to a safe state @@ -2514,7 +2510,7 @@ static void _add_datetime_offset(const dt_imgid_t imgid, g_free(datetime); } -static int32_t dt_control_datetime_job_run(dt_job_t *job) +static int32_t _control_datetime_job_run(dt_job_t *job) { dt_control_image_enumerator_t *params = dt_control_job_get_params(job); uint32_t cntr = 0; @@ -2548,6 +2544,7 @@ static int32_t dt_control_datetime_job_run(dt_job_t *job) for(GList *img = t; img; img = g_list_next(img)) { const dt_imgid_t imgid = GPOINTER_TO_INT(img->data); + if(!dt_is_valid_imgid(imgid)) continue; char odt[DT_DATETIME_LENGTH] = {0}; dt_image_get_datetime(imgid, odt); @@ -2593,44 +2590,44 @@ static int32_t dt_control_datetime_job_run(dt_job_t *job) return 0; } -static void *dt_control_datetime_alloc() +static void *_control_datetime_alloc() { - dt_control_image_enumerator_t *params = dt_control_image_enumerator_alloc(); + dt_control_image_enumerator_t *params = _control_image_enumerator_alloc(); if(!params) return NULL; params->data = calloc(1, sizeof(dt_control_datetime_t)); if(!params->data) { - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); return NULL; } return params; } -static void dt_control_datetime_job_cleanup(void *p) +static void _control_datetime_job_cleanup(void *p) { dt_control_image_enumerator_t *params = (dt_control_image_enumerator_t *)p; free(params->data); - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); } -static dt_job_t *dt_control_datetime_job_create(const GTimeSpan offset, +static dt_job_t *_control_datetime_job_create(const GTimeSpan offset, const char *datetime, GList *imgs) { - dt_job_t *job = dt_control_job_create(&dt_control_datetime_job_run, "time offset"); + dt_job_t *job = dt_control_job_create(&_control_datetime_job_run, "time offset"); if(!job) return NULL; - dt_control_image_enumerator_t *params = dt_control_datetime_alloc(); + dt_control_image_enumerator_t *params = _control_datetime_alloc(); if(!params) { dt_control_job_dispose(job); return NULL; } dt_control_job_add_progress(job, _("time offset"), FALSE); - dt_control_job_set_params(job, params, dt_control_datetime_job_cleanup); + dt_control_job_set_params(job, params, _control_datetime_job_cleanup); if(imgs) params->index = imgs; @@ -2651,15 +2648,14 @@ void dt_control_datetime(const GTimeSpan offset, const char *datetime, GList *imgs) { - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_datetime_job_create(offset, datetime, imgs)); + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_datetime_job_create(offset, datetime, imgs)); } void dt_control_write_sidecar_files() { - dt_control_add_job - (darktable.control, DT_JOB_QUEUE_USER_FG, - dt_control_generic_images_job_create(&dt_control_write_sidecar_files_job_run, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, + _control_generic_images_job_create(&_control_write_sidecar_files_job_run, N_("write sidecar files"), 0, NULL, PROGRESS_CANCELLABLE, FALSE)); } @@ -2955,12 +2951,12 @@ static void _control_import_job_cleanup(void *p) free(data); for(GList *img = params->index; img; img = g_list_next(img)) g_free(img->data); - dt_control_image_enumerator_cleanup(params); + _control_image_enumerator_cleanup(params); } static void *_control_import_alloc() { - dt_control_image_enumerator_t *params = dt_control_image_enumerator_alloc(); + dt_control_image_enumerator_t *params = _control_image_enumerator_alloc(); if(!params) return NULL; params->data = g_malloc0(sizeof(dt_control_import_t)); @@ -3012,7 +3008,7 @@ void dt_control_import(GList *imgs, const gboolean inplace) { gboolean wait = !imgs->next && inplace; - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, _control_import_job_create(imgs, datetime_override, inplace, wait ? &wait : NULL)); // if import in place single image => synchronous import diff --git a/src/control/jobs/control_jobs.h b/src/control/jobs/control_jobs.h index 7162f7fc02a1..476f95b7f211 100644 --- a/src/control/jobs/control_jobs.h +++ b/src/control/jobs/control_jobs.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2010-2024 darktable developers. + Copyright (C) 2010-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -28,34 +28,34 @@ G_BEGIN_DECLS -void dt_control_gpx_apply(const gchar *filename, int32_t filmid, const gchar *tz, GList *imgs); +void dt_control_gpx_apply(const gchar *filename, const int32_t filmid, const gchar *tz, GList *imgs); void dt_control_datetime(const GTimeSpan offset, const char *datetime, GList *imgs); -void dt_control_write_sidecar_files(); -void dt_control_delete_images(); -void dt_control_delete_image(dt_imgid_t imgid); -void dt_control_duplicate_images(gboolean virgin); +void dt_control_write_sidecar_files(void); +void dt_control_delete_images(void); +void dt_control_delete_image(const dt_imgid_t imgid); +void dt_control_duplicate_images(const gboolean virgin); void dt_control_flip_images(const int32_t cw); void dt_control_monochrome_images(const int32_t mode); -gboolean dt_control_remove_images(); -void dt_control_move_images(); -void dt_control_copy_images(); +gboolean dt_control_remove_images(void); +void dt_control_move_images(void); +void dt_control_copy_images(void); void dt_control_compress_history(GList *imgs); void dt_control_discard_history(GList *imgs); void dt_control_paste_history(GList *imgs); void dt_control_paste_parts_history(GList *imgs); -void dt_control_apply_styles(GList *imgs, GList *styles, gboolean duplicate); -void dt_control_set_local_copy_images(); -void dt_control_reset_local_copy_images(); -void dt_control_export(GList *imgid_list, int max_width, int max_height, int format_index, int storage_index, - gboolean high_quality, gboolean upscale, gboolean dimensions_scale, gboolean export_masks, - char *style, gboolean style_append, +void dt_control_apply_styles(GList *imgs, GList *styles, const gboolean duplicate); +void dt_control_set_local_copy_images(void); +void dt_control_reset_local_copy_images(void); +void dt_control_export(GList *imgid_list, const int max_width, const int max_height, const int format_index, const int storage_index, + const gboolean high_quality, const gboolean upscale, const gboolean dimensions_scale, const gboolean export_masks, + char *style, const gboolean style_append, dt_colorspaces_color_profile_type_t icc_type, const gchar *icc_filename, dt_iop_color_intent_t icc_intent, const gchar *metadata_export); -void dt_control_merge_hdr(); +void dt_control_merge_hdr(void); void dt_control_import(GList *imgs, const char *datetime_override, const gboolean inplace); -void dt_control_refresh_exif(); +void dt_control_refresh_exif(void); G_END_DECLS diff --git a/src/control/jobs/sidecar_jobs.c b/src/control/jobs/sidecar_jobs.c index b036905a2c89..866e1cf105de 100644 --- a/src/control/jobs/sidecar_jobs.c +++ b/src/control/jobs/sidecar_jobs.c @@ -172,7 +172,7 @@ void dt_control_sidecar_synch_start() { return; } - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_FG, job); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_FG, job); background_running = TRUE; } diff --git a/src/control/progress.c b/src/control/progress.c index b665ff76451d..a99201f59879 100644 --- a/src/control/progress.c +++ b/src/control/progress.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2014-2023 darktable developers. + Copyright (C) 2014-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -248,7 +248,7 @@ static void global_progress_end(dt_control_t *control, dt_progress_t *progress) #endif } -void dt_control_progress_init(dt_control_t *control) +void dt_control_progress_init(void) { #ifndef _WIN32 @@ -259,7 +259,7 @@ void dt_control_progress_init(dt_control_t *control) #else - if(darktable.dbus->dbus_connection) + if(darktable.dbus && darktable.dbus->dbus_connection) { GError *error = NULL; @@ -295,10 +295,13 @@ void dt_control_progress_init(dt_control_t *control) #endif // _WIN32 } -dt_progress_t *dt_control_progress_create(dt_control_t *control, gboolean has_progress_bar, +dt_progress_t *dt_control_progress_create(const gboolean has_progress_bar, const gchar *message) { // create the object + dt_control_t *control = darktable.control; + if(!control) return NULL; + dt_progress_t *progress = calloc(1, sizeof(dt_progress_t)); dt_pthread_mutex_init(&(progress->mutex), NULL); @@ -323,8 +326,9 @@ dt_progress_t *dt_control_progress_create(dt_control_t *control, gboolean has_pr return progress; } -void dt_control_progress_destroy(dt_control_t *control, dt_progress_t *progress) +void dt_control_progress_destroy(dt_progress_t *progress) { + dt_control_t *control = darktable.control; if(!control || !progress) return; dt_pthread_mutex_lock(&control->progress_system.mutex); @@ -345,9 +349,11 @@ void dt_control_progress_destroy(dt_control_t *control, dt_progress_t *progress) free(progress); } -void dt_control_progress_make_cancellable(dt_control_t *control, dt_progress_t *progress, - dt_progress_cancel_callback_t cancel, void *data) +void dt_control_progress_make_cancellable(dt_progress_t *progress, + dt_progress_cancel_callback_t cancel, + void *data) { + dt_control_t *control = darktable.control; if(!control || !progress) return; // set the value dt_pthread_mutex_lock(&progress->mutex); @@ -369,13 +375,13 @@ static void _control_progress_cancel_callback(dt_progress_t *progress, void *dat dt_control_job_cancel((dt_job_t *)data); } -void dt_control_progress_attach_job(dt_control_t *control, dt_progress_t *progress, dt_job_t *job) +void dt_control_progress_attach_job(dt_progress_t *progress, dt_job_t *job) { - if(control && progress && job) - dt_control_progress_make_cancellable(control, progress, &_control_progress_cancel_callback, job); + if(progress && job) + dt_control_progress_make_cancellable(progress, &_control_progress_cancel_callback, job); } -void dt_control_progress_cancel(dt_control_t *control, dt_progress_t *progress) +void dt_control_progress_cancel(dt_progress_t *progress) { if(!progress) return; dt_pthread_mutex_lock(&progress->mutex); @@ -410,8 +416,9 @@ Otherwise, do the cancel callback in mutex locked state as the progress struct w // the gui doesn't need to know I guess, it wouldn't to anything with that bit of information } -void dt_control_progress_set_progress(dt_control_t *control, dt_progress_t *progress, const double value) +void dt_control_progress_set_progress(dt_progress_t *progress, double value) { + dt_control_t *control = darktable.control; if(!control || !progress) return; dt_pthread_mutex_lock(&progress->mutex); @@ -446,8 +453,9 @@ const gchar *dt_control_progress_get_message(dt_progress_t *progress) return res; } -void dt_control_progress_set_message(dt_control_t *control, dt_progress_t *progress, const char *message) +void dt_control_progress_set_message(dt_progress_t *progress, const char *message) { + dt_control_t *control = darktable.control; if(!control || !progress) return; dt_pthread_mutex_lock(&progress->mutex); g_free(progress->message); diff --git a/src/control/progress.h b/src/control/progress.h index db2b4d38af13..7b5757af2cfa 100644 --- a/src/control/progress.h +++ b/src/control/progress.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2014-2020 darktable developers. + Copyright (C) 2014-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -29,34 +29,31 @@ typedef struct _dt_progress_t dt_progress_t; typedef void (*dt_progress_cancel_callback_t)(dt_progress_t *progress, void *data); /* init the progress system, basically making sure that any global progress bar is hidden */ -void dt_control_progress_init(struct dt_control_t *control); +void dt_control_progress_init(void); /** create a new progress object and add it to the gui. pass it to dt_control_progress_destroy() to free the * resources. */ -dt_progress_t *dt_control_progress_create(struct dt_control_t *control, gboolean has_progress_bar, - const gchar *message); +dt_progress_t *dt_control_progress_create(const gboolean has_progress_bar, const gchar *message); /** free the resources and remove the gui. */ -void dt_control_progress_destroy(struct dt_control_t *control, dt_progress_t *progress); +void dt_control_progress_destroy(dt_progress_t *progress); /** set a callback to be executed when the progress is being cancelled. */ -void dt_control_progress_make_cancellable(struct dt_control_t *control, dt_progress_t *progress, - dt_progress_cancel_callback_t cancel, void *data); +void dt_control_progress_make_cancellable(dt_progress_t *progress, dt_progress_cancel_callback_t cancel, void *data); /** convenience function to cancel a job when the progress gets cancelled. */ -void dt_control_progress_attach_job(struct dt_control_t *control, dt_progress_t *progress, - struct _dt_job_t *job); +void dt_control_progress_attach_job(dt_progress_t *progress, struct _dt_job_t *job); /** cancel the job linked to with dt_control_progress_attach_job(). don't forget to call * dt_control_progress_destroy() afterwards. */ -void dt_control_progress_cancel(struct dt_control_t *control, dt_progress_t *progress); +void dt_control_progress_cancel(dt_progress_t *progress); /** update the progress of the progress object. the range should be [0.0, 1.0] to make progress bars work. */ -void dt_control_progress_set_progress(struct dt_control_t *control, dt_progress_t *progress, double value); +void dt_control_progress_set_progress(dt_progress_t *progress, const double value); /** return the last set progress value. */ double dt_control_progress_get_progress(dt_progress_t *progress); /** get the message passed during construction. */ const gchar *dt_control_progress_get_message(dt_progress_t *progress); /** update the message. */ -void dt_control_progress_set_message(struct dt_control_t *control, dt_progress_t *progress, const char *message); +void dt_control_progress_set_message(dt_progress_t *progress, const char *message); /** these functions are to be used by lib/backgroundjobs.c only. */ void dt_control_progress_set_gui_data(dt_progress_t *progress, void *data); diff --git a/src/develop/blend_gui.c b/src/develop/blend_gui.c index 8332ab292db3..496ba3ef44f1 100644 --- a/src/develop/blend_gui.c +++ b/src/develop/blend_gui.c @@ -1420,7 +1420,7 @@ static gboolean _blendop_masks_modes_none_clicked(GtkWidget *button, dt_iop_add_remove_mask_indicator(module, FALSE); /* and finally remove hinter messages */ - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); } return TRUE; @@ -1707,7 +1707,7 @@ static gboolean _blendop_masks_show_and_edit(GtkWidget *widget, { bd->masks_shown = DT_MASKS_EDIT_OFF; /* remove hinter messages */ - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); } gtk_toggle_button_set_active diff --git a/src/develop/develop.c b/src/develop/develop.c index 19ff1b7bba20..c385d6171ee7 100644 --- a/src/develop/develop.c +++ b/src/develop/develop.c @@ -223,26 +223,20 @@ void dt_dev_cleanup(dt_develop_t *dev) void dt_dev_process_image(dt_develop_t *dev) { if(!dev->gui_attached || dev->full.pipe->processing) return; - const gboolean err - = dt_control_add_job_res(darktable.control, - dt_dev_process_image_job_create(dev), DT_CTL_WORKER_ZOOM_1); + const gboolean err = dt_control_add_job_res(dt_dev_process_image_job_create(dev), DT_CTL_WORKER_ZOOM_1); if(err) dt_print(DT_DEBUG_ALWAYS, "[dev_process_image] job queue exceeded!"); } void dt_dev_process_preview(dt_develop_t *dev) { if(!dev->gui_attached) return; - const gboolean err = dt_control_add_job_res(darktable.control, - dt_dev_process_preview_job_create(dev), - DT_CTL_WORKER_ZOOM_FILL); + const gboolean err = dt_control_add_job_res(dt_dev_process_preview_job_create(dev), DT_CTL_WORKER_ZOOM_FILL); if(err) dt_print(DT_DEBUG_ALWAYS, "[dev_process_preview] job queue exceeded!"); } void dt_dev_process_preview2(dt_develop_t *dev) { - const gboolean err = dt_control_add_job_res(darktable.control, - dt_dev_process_preview2_job_create(dev), - DT_CTL_WORKER_ZOOM_2); + const gboolean err = dt_control_add_job_res(dt_dev_process_preview2_job_create(dev), DT_CTL_WORKER_ZOOM_2); if(err) dt_print(DT_DEBUG_ALWAYS, "[dev_process_preview2] job queue exceeded!"); } diff --git a/src/develop/masks/masks.c b/src/develop/masks/masks.c index dd6747579142..60ae0d5a3f06 100644 --- a/src/develop/masks/masks.c +++ b/src/develop/masks/masks.c @@ -168,7 +168,7 @@ static void _set_hinter_message(dt_masks_form_gui_t *gui, sel->functions->set_hint_message(gui, form, opacity, msg, sizeof(msg)); } - dt_control_hinter_message(darktable.control, msg); + dt_control_hinter_message(msg); } void dt_masks_init_form_gui(dt_masks_form_gui_t *gui) @@ -1085,7 +1085,7 @@ gboolean dt_masks_events_mouse_leave(dt_iop_module_t *module) gui->posx = (.5f + zoom_x) * wd; gui->posy = (.5f + zoom_y) * ht; - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); } return FALSE; } diff --git a/src/gui/gtk.c b/src/gui/gtk.c index d347ca85a338..6d3448739f3b 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -330,7 +330,7 @@ static void _panel_toggle(dt_ui_border_t border, dt_ui_panel_show(ui, DT_UI_PANEL_CENTER_TOP, TRUE, TRUE); else dt_ui_panel_show(ui, DT_UI_PANEL_TOP, TRUE, TRUE); - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); } break; diff --git a/src/iop/clipping.c b/src/iop/clipping.c index d12c7cc67c1d..9385292791b3 100644 --- a/src/iop/clipping.c +++ b/src/iop/clipping.c @@ -3014,11 +3014,11 @@ int mouse_moved(dt_iop_module_t *self, dt_control_change_cursor(GDK_BOTTOM_LEFT_CORNER); else if(grab == GRAB_NONE) { - dt_control_hinter_message(darktable.control, _("commit: double-click, straighten: right-drag")); + dt_control_hinter_message(_("commit: double-click, straighten: right-drag")); dt_control_change_cursor(GDK_LEFT_PTR); } if(grab != GRAB_NONE) - dt_control_hinter_message(darktable.control, _("resize: drag, keep aspect ratio: shift+drag\n" + dt_control_hinter_message(_("resize: drag, keep aspect ratio: shift+drag\n" "straighten: right-drag")); dt_control_queue_redraw_center(); } @@ -3059,24 +3059,24 @@ int mouse_moved(dt_iop_module_t *self, } if(g->k_selected >= 0) { - dt_control_hinter_message(darktable.control, _("move control point: drag")); + dt_control_hinter_message(_("move control point: drag")); dt_control_change_cursor(GDK_CROSS); } else if(g->k_selected_segment >= 0) { - dt_control_hinter_message(darktable.control, _("move line: drag, toggle symmetry: click ꝏ")); + dt_control_hinter_message(_("move line: drag, toggle symmetry: click ꝏ")); dt_control_change_cursor(GDK_CROSS); } else { - dt_control_hinter_message(darktable.control, _("apply: click ok, toggle symmetry: click ꝏ\n" + dt_control_hinter_message(_("apply: click ok, toggle symmetry: click ꝏ\n" "move line/control point: drag")); dt_control_change_cursor(GDK_FLEUR); } } else { - dt_control_hinter_message(darktable.control, _("move: drag, move vertically: shift+drag, move horizontally: ctrl+drag\n" + dt_control_hinter_message(_("move: drag, move vertically: shift+drag, move horizontally: ctrl+drag\n" "straighten: right-drag, commit: double-click")); } dt_control_queue_redraw_center(); diff --git a/src/iop/crop.c b/src/iop/crop.c index ed6ee7ba52b3..fa1cec0fd7be 100644 --- a/src/iop/crop.c +++ b/src/iop/crop.c @@ -1684,22 +1684,18 @@ int mouse_moved(dt_iop_module_t *self, dt_control_change_cursor(GDK_BOTTOM_LEFT_CORNER); else if(grab == GRAB_NONE) { - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); dt_control_change_cursor(GDK_LEFT_PTR); } if(grab != GRAB_NONE) - dt_control_hinter_message - (darktable.control, - _("resize: drag, keep aspect ratio: shift+drag")); + dt_control_hinter_message(_("resize: drag, keep aspect ratio: shift+drag")); dt_control_queue_redraw_center(); } else { dt_control_change_cursor(GDK_FLEUR); g->cropping = GRAB_CENTER; - dt_control_hinter_message - (darktable.control, - _("move: drag, move vertically: shift+drag, " + dt_control_hinter_message(_("move: drag, move vertically: shift+drag, " "move horizontally: ctrl+drag")); dt_control_queue_redraw_center(); } diff --git a/src/iop/liquify.c b/src/iop/liquify.c index 658dc0794a1b..f268a75883bf 100644 --- a/src/iop/liquify.c +++ b/src/iop/liquify.c @@ -2842,7 +2842,7 @@ int mouse_moved(dt_iop_module_t *self, if(last_hovered) last_hovered->header.hovered = 0; // change in hover display - dt_control_hinter_message(darktable.control, dt_liquify_layers[hit.layer].hint); + dt_control_hinter_message(dt_liquify_layers[hit.layer].hint); // also use when dragging later dt_liquify_layers[DT_LIQUIFY_LAYER_BACKGROUND].hint = dt_liquify_layers[hit.layer].hint; @@ -2870,12 +2870,11 @@ int mouse_moved(dt_iop_module_t *self, } else if(hit.elem == DT_LIQUIFY_LAYER_BACKGROUND && gtk_toggle_button_get_active(g->btn_node_tool)) - dt_control_hinter_message(darktable.control, _("click to edit nodes")); + dt_control_hinter_message(_("click to edit nodes")); } else if(is_dragging(g)) // we are dragging { - dt_control_hinter_message(darktable.control, - dt_liquify_layers[DT_LIQUIFY_LAYER_BACKGROUND].hint); + dt_control_hinter_message(dt_liquify_layers[DT_LIQUIFY_LAYER_BACKGROUND].hint); dt_liquify_path_data_t *d = g->dragging.elem; dt_liquify_path_data_t *n = node_next(pa, d); @@ -3549,7 +3548,7 @@ static gboolean btn_make_radio_callback(GtkToggleButton *btn, g->creation_continuous = event != NULL && dt_modifier_is(event->state, GDK_CONTROL_MASK); - dt_control_hinter_message(darktable.control, ""); + dt_control_hinter_message(""); // if we are on a preview, it means that a form (point, line, curve) // has been started, but no node has yet been placed. in this case diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index 372125782b76..f159143e4971 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -2025,8 +2025,7 @@ static void switch_cursors(dt_iop_module_t *self) // if pipe is clean and idle and cursor is on preview, // hide GTK cursor because we display our custom one dt_control_change_cursor(GDK_BLANK_CURSOR); - dt_control_hinter_message(darktable.control, - _("scroll over image to change tone exposure\n" + dt_control_hinter_message(_("scroll over image to change tone exposure\n" "shift+scroll for large steps; " "ctrl+scroll for small steps")); @@ -2577,8 +2576,7 @@ void gui_focus(dt_iop_module_t *self, gboolean in) } else { - dt_control_hinter_message(darktable.control, - _("scroll over image to change tone exposure\n" + dt_control_hinter_message(_("scroll over image to change tone exposure\n" "shift+scroll for large steps; " "ctrl+scroll for small steps")); // listen to distort change again diff --git a/src/libs/backgroundjobs.c b/src/libs/backgroundjobs.c index f165d2466846..b791f704293f 100644 --- a/src/libs/backgroundjobs.c +++ b/src/libs/backgroundjobs.c @@ -224,7 +224,7 @@ static void _lib_backgroundjobs_destroyed(dt_lib_module_t *self, dt_lib_backgrou static void _lib_backgroundjobs_cancel_callback_new(GtkWidget *w, gpointer user_data) { dt_progress_t *progress = (dt_progress_t *)user_data; - dt_control_progress_cancel(darktable.control, progress); + dt_control_progress_cancel(progress); } typedef struct _cancellable_gui_thread_t diff --git a/src/libs/camera.c b/src/libs/camera.c index b7b3407548c8..3bfd996e074f 100644 --- a/src/libs/camera.c +++ b/src/libs/camera.c @@ -221,7 +221,7 @@ static void _capture_button_clicked(GtkWidget *widget, gpointer user_data) /* create a capture background job */ jobcode = dt_view_tethering_get_job_code(darktable.view_manager); - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_FG, + dt_control_add_job(DT_JOB_QUEUE_USER_FG, dt_camera_capture_job_create(jobcode, delay, count, brackets, steps)); } diff --git a/src/libs/import.c b/src/libs/import.c index 7bc62af62eb8..d9ad5c68a3ca 100644 --- a/src/libs/import.c +++ b/src/libs/import.c @@ -2311,7 +2311,7 @@ static void _import_from_dialog_run(dt_lib_module_t* self) #ifdef HAVE_GPHOTO2 if(d->import_case == DT_IMPORT_CAMERA) { - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, + dt_control_add_job(DT_JOB_QUEUE_USER_BG, dt_camera_import_job_create(imgs, d->camera, datetime_override)); } else diff --git a/src/libs/print_settings.c b/src/libs/print_settings.c index 7497ba2ab32d..a3d5a175d1d5 100644 --- a/src/libs/print_settings.c +++ b/src/libs/print_settings.c @@ -777,7 +777,7 @@ static void _print_button_clicked(GtkWidget *widget, dt_lib_module_t *self) params->p_icc_intent = ps->v_pintent; params->black_point_compensation = ps->v_black_point_compensation; - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_EXPORT, job); + dt_control_add_job(DT_JOB_QUEUE_USER_EXPORT, job); } static void _set_printer(const dt_lib_module_t *self, diff --git a/src/lua/gui.c b/src/lua/gui.c index f561411c289e..de35825d98fd 100644 --- a/src/lua/gui.c +++ b/src/lua/gui.c @@ -314,10 +314,10 @@ static int _lua_create_job(lua_State *L) luaL_checktype(L, 3, LUA_TFUNCTION); cancellable = TRUE; } - dt_progress_t *progress = dt_control_progress_create(darktable.control, has_progress_bar, message); + dt_progress_t *progress = dt_control_progress_create(has_progress_bar, message); if(cancellable) { - dt_control_progress_make_cancellable(darktable.control, progress, _lua_job_cancelled, progress); + dt_control_progress_make_cancellable(progress, _lua_job_cancelled, progress); } luaA_push(L, dt_lua_backgroundjob_t, &progress); if(cancellable) @@ -351,7 +351,7 @@ static int _lua_job_progress(lua_State *L) { double value; luaA_to(L, progress_double, &value, 3); - dt_control_progress_set_progress(darktable.control, progress, value); + dt_control_progress_set_progress(progress, value); return 0; } } @@ -377,7 +377,7 @@ static int _lua_job_valid(lua_State *L) { int validity = lua_toboolean(L, 3); if(validity) return luaL_argerror(L, 3, "a job can not be made valid"); - dt_control_progress_destroy(darktable.control, progress); + dt_control_progress_destroy(progress); return 0; } } diff --git a/src/lua/luastorage.c b/src/lua/luastorage.c index f92a808f63d1..a939bbefa13e 100644 --- a/src/lua/luastorage.c +++ b/src/lua/luastorage.c @@ -327,7 +327,7 @@ static void free_params_wrapper(struct dt_imageio_module_storage_t *self, } dt_control_job_set_params(job, t, free_param_wrapper_destroy); t->data = (lua_storage_t *)data; - dt_control_add_job(darktable.control, DT_JOB_QUEUE_SYSTEM_BG, job); + dt_control_add_job(DT_JOB_QUEUE_SYSTEM_BG, job); } static int set_params_wrapper(struct dt_imageio_module_storage_t *self, diff --git a/src/lua/print.c b/src/lua/print.c index 295ba72552a4..be2c862a8a1b 100644 --- a/src/lua/print.c +++ b/src/lua/print.c @@ -53,7 +53,7 @@ static int lua_print_hinter(lua_State *L) char msg[256]; if(snprintf(msg, sizeof(msg), "%s", luaL_checkstring(L, -1)) > 0) { - dt_control_hinter_message(darktable.control, msg); + dt_control_hinter_message(msg); } } else diff --git a/src/views/slideshow.c b/src/views/slideshow.c index 63e4d80a4a66..ed25c300669c 100644 --- a/src/views/slideshow.c +++ b/src/views/slideshow.c @@ -180,7 +180,7 @@ static void _shift_right(dt_slideshow_t *d) static void _requeue_job(dt_slideshow_t *d) { - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, _process_job_create(d)); + dt_control_add_job(DT_JOB_QUEUE_USER_BG, _process_job_create(d)); } static void _set_delay(dt_slideshow_t *d, @@ -510,7 +510,7 @@ void enter(dt_view_t *self) // start first job dt_control_queue_redraw_center(); - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, _process_job_create(d)); + dt_control_add_job(DT_JOB_QUEUE_USER_BG, _process_job_create(d)); dt_control_log(_("waiting to start slideshow")); } diff --git a/src/views/tethering.c b/src/views/tethering.c index f3517820a17d..b4a96b92b9e4 100644 --- a/src/views/tethering.c +++ b/src/views/tethering.c @@ -552,7 +552,7 @@ static void _camera_capture_image_downloaded(const dt_camera_t *camera, dt_capture_t *lib = (dt_capture_t *)data; /* create an import job of downloaded image */ - dt_control_add_job(darktable.control, DT_JOB_QUEUE_USER_BG, + dt_control_add_job(DT_JOB_QUEUE_USER_BG, dt_image_import_job_create(dt_import_session_film_id(lib->session), filename)); } From cb403590e379a865b28ea2e98e6fa77a444712a8 Mon Sep 17 00:00:00 2001 From: Hanno Schwalm Date: Sat, 15 Feb 2025 13:22:27 +0100 Subject: [PATCH 2/3] Hide darktable.image_cache implementation details 1. We don't want/need to expose the usage of `darktable.image_cache' in all functions using the image_cache for denser code and readability. 2. Allocation and free image_cache is done inside the init/cleanup functions 3. Some additional safety checks for dereferencing making sure operations are done only with a valid dt_image_t 4. Some leading underscore renaming for static functions 5. Some asserts added for debugging builds --- src/cli/main.c | 4 +- src/common/act_on.c | 4 +- src/common/darktable.c | 8 +- src/common/exif.cc | 4 +- src/common/film.c | 2 +- src/common/focus.h | 4 +- src/common/gimp.c | 4 +- src/common/grouping.c | 47 +++++----- src/common/history.c | 16 ++-- src/common/image.c | 157 ++++++++++++++------------------ src/common/image.h | 5 +- src/common/image_cache.c | 110 ++++++++++++---------- src/common/image_cache.h | 42 +++------ src/common/mipmap_cache.c | 36 ++++---- src/common/ratings.c | 13 ++- src/common/selection.c | 8 +- src/common/styles.c | 2 +- src/common/undo.c | 2 +- src/common/variables.c | 8 +- src/control/jobs/control_jobs.c | 63 +++++++------ src/control/jobs/image_jobs.c | 2 +- src/develop/develop.c | 19 ++-- src/dtgtk/thumbnail.c | 24 ++--- src/dtgtk/thumbtable.c | 3 +- src/imageio/storage/disk.c | 9 +- src/imageio/storage/email.c | 12 +-- src/imageio/storage/piwigo.c | 4 +- src/iop/colorin.c | 22 ++--- src/iop/demosaic.c | 4 +- src/iop/exposure.c | 7 +- src/iop/rawprepare.c | 4 +- src/libs/copy_history.c | 4 +- src/libs/geotagging.c | 8 +- src/libs/histogram.c | 10 +- src/libs/image.c | 4 +- src/libs/lib.c | 6 +- src/libs/live_view.c | 6 +- src/libs/metadata_view.c | 10 +- src/libs/modulegroups.c | 5 +- src/libs/print_settings.c | 13 +-- src/lua/image.c | 17 ++-- src/views/darkroom.c | 12 +-- src/views/print.c | 10 +- 43 files changed, 356 insertions(+), 398 deletions(-) diff --git a/src/cli/main.c b/src/cli/main.c index d8da95ede7fa..826133450c8b 100644 --- a/src/cli/main.c +++ b/src/cli/main.c @@ -600,7 +600,7 @@ int main(int argc, char *arg[]) for(GList *iter = id_list; iter; iter = g_list_next(iter)) { int id = GPOINTER_TO_INT(iter->data); - dt_image_t *image = dt_image_cache_get(darktable.image_cache, id, 'w'); + dt_image_t *image = dt_image_cache_get(id, 'w'); if(dt_exif_xmp_read(image, xmp_filename, 1)) { fprintf(stderr, _("error: can't open XMP file %s"), xmp_filename); @@ -612,7 +612,7 @@ int main(int argc, char *arg[]) exit(1); } // don't write new xmp: - dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(image, DT_IMAGE_CACHE_RELAXED); } } diff --git a/src/common/act_on.c b/src/common/act_on.c index 4cee0ce52b87..c4e90472b744 100644 --- a/src/common/act_on.c +++ b/src/common/act_on.c @@ -44,11 +44,11 @@ static void _insert_in_list(GList **list, return; } - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); if(image) { const dt_imgid_t img_group_id = image->group_id; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); if(!darktable.gui || !darktable.gui->grouping diff --git a/src/common/darktable.c b/src/common/darktable.c index 896173cd6b02..9730c4cbe882 100644 --- a/src/common/darktable.c +++ b/src/common/darktable.c @@ -1745,8 +1745,7 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load // 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); + dt_image_cache_init(); darktable.mipmap_cache = (dt_mipmap_cache_t *)calloc(1, sizeof(dt_mipmap_cache_t)); dt_mipmap_cache_init(darktable.mipmap_cache); @@ -2093,10 +2092,7 @@ void dt_cleanup() dt_control_cleanup(FALSE); - dt_image_cache_cleanup(darktable.image_cache); - free(darktable.image_cache); - darktable.image_cache = NULL; - + dt_image_cache_cleanup(); dt_mipmap_cache_cleanup(darktable.mipmap_cache); free(darktable.mipmap_cache); darktable.mipmap_cache = NULL; diff --git a/src/common/exif.cc b/src/common/exif.cc index 36bbf7d44e9a..cac922a1e20a 100644 --- a/src/common/exif.cc +++ b/src/common/exif.cc @@ -2805,7 +2805,7 @@ int dt_exif_read_blob(uint8_t **buf, // GPS data _remove_exif_geotag(exifData); - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(imgid, 'r'); if(cimg && !std::isnan(cimg->geoloc.longitude) && !std::isnan(cimg->geoloc.latitude)) { exifData["Exif.GPSInfo.GPSVersionID"] = "02 02 00 00"; @@ -2853,7 +2853,7 @@ int dt_exif_read_blob(uint8_t **buf, if(g_strcmp0(&datetime[DT_DATETIME_EXIF_LENGTH], "000")) exifData["Exif.Photo.SubSecTimeOriginal"] = &datetime[DT_DATETIME_EXIF_LENGTH]; - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); } Exiv2::Blob blob; diff --git a/src/common/film.c b/src/common/film.c index 678dd761b99c..7884b6f3e631 100644 --- a/src/common/film.c +++ b/src/common/film.c @@ -488,7 +488,7 @@ void dt_film_remove(const dt_filmid_t id) const dt_imgid_t imgid = sqlite3_column_int(stmt, 0); dt_image_local_copy_reset(imgid); dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); - dt_image_cache_remove(darktable.image_cache, imgid); + dt_image_cache_remove(imgid); } sqlite3_finalize(stmt); diff --git a/src/common/focus.h b/src/common/focus.h index f6e40bb2f7a7..24b0e0467b27 100644 --- a/src/common/focus.h +++ b/src/common/focus.h @@ -207,9 +207,9 @@ static void dt_focus_draw_clusters(cairo_t *cr, int width, int height, dt_imgid_ cairo_save(cr); cairo_translate(cr, width / 2.0, height / 2.0f); - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); dt_image_t image = *img; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); // FIXME: get those from rawprepare IOP somehow !!! int wd = buffer_width + image.crop_x; diff --git a/src/common/gimp.c b/src/common/gimp.c index f8017f2fc1e4..61485e292593 100644 --- a/src/common/gimp.c +++ b/src/common/gimp.c @@ -64,9 +64,9 @@ gboolean dt_export_gimp_file(const dt_imgid_t imgid) printf("<<width, image->height); - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); } printf("gimp>>>\n"); res = TRUE; diff --git a/src/common/grouping.c b/src/common/grouping.c index 1e1ddf4c74a9..c45354f49856 100644 --- a/src/common/grouping.c +++ b/src/common/grouping.c @@ -38,17 +38,16 @@ void dt_grouping_add_to_group(const dt_imgid_t group_id, // remove from old group dt_grouping_remove_from_group(image_id); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'w'); + dt_image_t *img = dt_image_cache_get(image_id, 'w'); if(!img) return; img->group_id = group_id; - dt_image_cache_write_release_info(darktable.image_cache, img, - DT_IMAGE_CACHE_SAFE, "dt_grouping_add_to_group"); + dt_image_cache_write_release_info(img, DT_IMAGE_CACHE_SAFE, "dt_grouping_add_to_group"); GList *imgs = NULL; imgs = g_list_prepend(imgs, GINT_TO_POINTER(image_id)); DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_IMAGE_INFO_CHANGED, imgs); #ifdef USE_LUA - dt_lua_async_call_alien(dt_lua_event_trigger_wrapper, + dt_lua_async_call_alien(dt_lua_event_trigger_wrapper, 0, NULL, NULL, LUA_ASYNC_TYPENAME, "const char*", "image-group-information-changed", LUA_ASYNC_TYPENAME, "const char*", "add", @@ -65,9 +64,9 @@ dt_imgid_t dt_grouping_remove_from_group(const dt_imgid_t image_id) dt_imgid_t new_group_id = NO_IMGID; GList *imgs = NULL; - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r'); + const dt_image_t *img = dt_image_cache_get(image_id, 'r'); const dt_imgid_t img_group_id = img ? img->group_id : NO_IMGID; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); if(img_group_id == image_id) { // get a new group_id for all the others in the group. also write @@ -84,12 +83,11 @@ dt_imgid_t dt_grouping_remove_from_group(const dt_imgid_t image_id) dt_imgid_t other_id = sqlite3_column_int(stmt, 0); if(!dt_is_valid_imgid(new_group_id)) new_group_id = other_id; - dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w'); + dt_image_t *other_img = dt_image_cache_get(other_id, 'w'); if(other_img) { other_img->group_id = new_group_id; - dt_image_cache_write_release_info(darktable.image_cache, other_img, - DT_IMAGE_CACHE_SAFE, "dt_grouping_add_to_group"); + dt_image_cache_write_release_info(other_img, DT_IMAGE_CACHE_SAFE, "dt_grouping_add_to_group"); imgs = g_list_prepend(imgs, GINT_TO_POINTER(other_id)); } } @@ -125,13 +123,13 @@ dt_imgid_t dt_grouping_remove_from_group(const dt_imgid_t image_id) else { // change the group_id for this image. - dt_image_t *wimg = dt_image_cache_get(darktable.image_cache, image_id, 'w'); + dt_image_t *wimg = dt_image_cache_get(image_id, 'w'); if(wimg) { new_group_id = wimg->group_id; wimg->group_id = image_id; - dt_image_cache_write_release_info(darktable.image_cache, wimg, - DT_IMAGE_CACHE_SAFE, "dt_grouping_add_to_group"); + dt_image_cache_write_release_info(wimg, DT_IMAGE_CACHE_SAFE, "dt_grouping_add_to_group"); + imgs = g_list_prepend(imgs, GINT_TO_POINTER(image_id)); // refresh also the group leader which may be alone now imgs = g_list_prepend(imgs, GINT_TO_POINTER(img_group_id)); @@ -156,26 +154,27 @@ dt_imgid_t dt_grouping_change_representative(const dt_imgid_t image_id) { sqlite3_stmt *stmt; - dt_image_t *img = dt_image_cache_get(darktable.image_cache, image_id, 'r'); + dt_image_t *img = dt_image_cache_get(image_id, 'r'); const dt_imgid_t group_id = img ? img->group_id : NO_IMGID; - dt_image_cache_read_release(darktable.image_cache, img); - if(!dt_is_valid_imgid(group_id)) + dt_image_cache_read_release(img); + + if(!dt_is_valid_imgid(group_id)) return group_id; GList *imgs = NULL; - DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE group_id = ?1", -1, + DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), + "SELECT id FROM main.images WHERE group_id = ?1", -1, &stmt, NULL); DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, group_id); while(sqlite3_step(stmt) == SQLITE_ROW) { const dt_imgid_t other_id = sqlite3_column_int(stmt, 0); - dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w'); + dt_image_t *other_img = dt_image_cache_get(other_id, 'w'); if(other_img) { other_img->group_id = image_id; - dt_image_cache_write_release_info(darktable.image_cache, other_img, - DT_IMAGE_CACHE_SAFE, - "dt_grouping_change_representative"); + dt_image_cache_write_release_info(other_img, DT_IMAGE_CACHE_SAFE, + "dt_grouping_change_representative"); imgs = g_list_prepend(imgs, GINT_TO_POINTER(other_id)); } } @@ -199,11 +198,11 @@ dt_imgid_t dt_grouping_change_representative(const dt_imgid_t image_id) GList *dt_grouping_get_group_images(const dt_imgid_t imgid) { GList *imgs = NULL; - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); if(image) { const dt_imgid_t img_group_id = image->group_id; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); if(darktable.gui && darktable.gui->grouping && darktable.gui->expanded_group_id != img_group_id) { sqlite3_stmt *stmt; @@ -230,11 +229,11 @@ void dt_grouping_add_grouped_images(GList **images) GList *gimgs = NULL; for(GList *imgs = *images; imgs; imgs = g_list_next(imgs)) { - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, GPOINTER_TO_INT(imgs->data), 'r'); + const dt_image_t *image = dt_image_cache_get(GPOINTER_TO_INT(imgs->data), 'r'); if(image) { const dt_imgid_t img_group_id = image->group_id; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); if(darktable.gui && darktable.gui->grouping && darktable.gui->expanded_group_id != img_group_id && dt_selection_get_collection(darktable.selection)) { diff --git a/src/common/history.c b/src/common/history.c index 27c9e7355028..23872da6f6bf 100644 --- a/src/common/history.c +++ b/src/common/history.c @@ -47,14 +47,14 @@ void dt_history_item_free(gpointer data) static void _remove_preset_flag(const dt_imgid_t imgid) { - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); // clear flag if(image) image->flags &= ~DT_IMAGE_AUTO_PRESETS_APPLIED; // write through to sql+xmp - dt_image_cache_write_release_info(darktable.image_cache, image, + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_SAFE, "_remove_preset_flag"); } @@ -139,7 +139,7 @@ void dt_history_delete_on_image_ext(const dt_imgid_t imgid, DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_TAG_CHANGED); /* unset change timestamp */ - dt_image_cache_unset_change_timestamp(darktable.image_cache, imgid); + dt_image_cache_unset_change_timestamp(imgid); // signal that the mipmap need to be updated DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_DEVELOP_MIPMAP_UPDATED, imgid); @@ -173,7 +173,7 @@ gboolean dt_history_load_and_apply(const dt_imgid_t imgid, const gboolean history_only) { dt_lock_image(imgid); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); if(img) { dt_undo_lt_history_t *hist = dt_history_snapshot_item_init(); @@ -182,8 +182,7 @@ gboolean dt_history_load_and_apply(const dt_imgid_t imgid, if(dt_exif_xmp_read(img, filename, history_only)) { - dt_image_cache_write_release_info - (darktable.image_cache, img, + dt_image_cache_write_release_info(img, // ugly but if not history_only => called from crawler - do not write the xmp history_only ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED, "dt_history_load_and_apply"); @@ -201,8 +200,7 @@ gboolean dt_history_load_and_apply(const dt_imgid_t imgid, if(dt_dev_is_current_image(darktable.develop, imgid)) dt_dev_reload_history_items(darktable.develop); - dt_image_cache_write_release_info - (darktable.image_cache, img, + dt_image_cache_write_release_info(img, // ugly but if not history_only => called from crawler - do not write the xmp history_only ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED, "dt_history_load_and_apply"); @@ -974,7 +972,7 @@ gboolean dt_history_copy_and_paste_on_image(const dt_imgid_t imgid, dt_tag_new("darktable|changed", &tagid); dt_tag_attach(tagid, dest_imgid, FALSE, FALSE); /* set change_timestamp */ - dt_image_cache_set_change_timestamp(darktable.image_cache, dest_imgid); + dt_image_cache_set_change_timestamp(dest_imgid); /* if current image in develop reload history */ if(dt_dev_is_current_image(darktable.develop, dest_imgid)) diff --git a/src/common/image.c b/src/common/image.c index 2c7e814e500b..cdeb42259aff 100644 --- a/src/common/image.c +++ b/src/common/image.c @@ -190,30 +190,30 @@ static void _image_set_monochrome_flag(const dt_imgid_t imgid, { gboolean changed = FALSE; - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *img = dt_image_cache_get(imgid, 'r'); if(img) { const int mask_bw = dt_image_monochrome_flags(img); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); if((!monochrome) && (mask_bw & DT_IMAGE_MONOCHROME_PREVIEW)) { // wanting it to be color found preview - img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + img = dt_image_cache_get(imgid, 'w'); img->flags &= ~(DT_IMAGE_MONOCHROME_PREVIEW | DT_IMAGE_MONOCHROME_WORKFLOW); changed = TRUE; } if(monochrome && ((mask_bw == 0) || (mask_bw == DT_IMAGE_MONOCHROME_PREVIEW))) { // wanting monochrome and found color or just preview without workflow activation - img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + img = dt_image_cache_get(imgid, 'w'); img->flags |= (DT_IMAGE_MONOCHROME_PREVIEW | DT_IMAGE_MONOCHROME_WORKFLOW); changed = TRUE; } if(changed) { const int mask = dt_image_monochrome_flags(img); - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); dt_imageio_update_monochrome_workflow_tag(imgid, mask); if(undo_on) @@ -599,38 +599,36 @@ void dt_image_set_xmp_rating(dt_image_t *img, const int rating) void dt_image_get_location(const dt_imgid_t imgid, dt_image_geoloc_t *geoloc) { - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); if(img) { geoloc->longitude = img->geoloc.longitude; geoloc->latitude = img->geoloc.latitude; geoloc->elevation = img->geoloc.elevation; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } } static void _set_location(const dt_imgid_t imgid, const dt_image_geoloc_t *geoloc) { /* fetch image from cache */ - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); if(image) memcpy(&image->geoloc, geoloc, sizeof(dt_image_geoloc_t)); - dt_image_cache_write_release_info(darktable.image_cache, image, - DT_IMAGE_CACHE_SAFE, "_set_location"); + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_SAFE, "_set_location"); } static void _set_datetime(const dt_imgid_t imgid, const char *datetime) { /* fetch image from cache */ - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); if(image) dt_datetime_exif_to_img(image, datetime); - dt_image_cache_write_release_info(darktable.image_cache, image, - DT_IMAGE_CACHE_SAFE, "_set_datetime"); + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_SAFE, "_set_datetime"); } static void _pop_undo(gpointer user_data, @@ -850,13 +848,13 @@ void dt_image_update_final_size(const dt_imgid_t imgid) darktable.develop->full.pipe->iheight, &ww, &hh); - dt_image_t *imgtmp = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *imgtmp = dt_image_cache_get(imgid, 'w'); if(imgtmp) { const gboolean changed = (ww != imgtmp->final_width) || (hh != imgtmp->final_height); imgtmp->final_width = ww; imgtmp->final_height = hh; - dt_image_cache_write_release(darktable.image_cache, imgtmp, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(imgtmp, DT_IMAGE_CACHE_RELAXED); if(changed) { dt_print(DT_DEBUG_PIPE, "updated final size for ID=%i, updated to %ix%i", imgid, ww, hh); @@ -871,7 +869,7 @@ gboolean dt_image_get_final_size(const dt_imgid_t imgid, int *width, int *height { if(!dt_is_valid_imgid(imgid)) return TRUE; // get the img strcut - dt_image_t *timg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *timg = dt_image_cache_get(imgid, 'r'); if(!timg) { *width = 0; @@ -887,7 +885,7 @@ gboolean dt_image_get_final_size(const dt_imgid_t imgid, int *width, int *height *height = timg->final_height; dt_print(DT_DEBUG_PIPE, "[dt_image_get_final_size] for ID=%i from cache %ix%i", imgid, *width, *height); } - dt_image_cache_read_release(darktable.image_cache, timg); + dt_image_cache_read_release(timg); if(available) return FALSE; // we have to do the costly pipe run to get the final image size @@ -915,12 +913,12 @@ gboolean dt_image_get_final_size(const dt_imgid_t imgid, int *width, int *height } dt_dev_cleanup(&dev); - dt_image_t * imgwr = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *imgwr = dt_image_cache_get(imgid, 'w'); if(imgwr) { imgwr->final_width = *width = wd; imgwr->final_height = *height = ht; - dt_image_cache_write_release(darktable.image_cache, imgwr, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(imgwr, DT_IMAGE_CACHE_RELAXED); } return res; } @@ -980,7 +978,7 @@ void dt_image_set_flip(const dt_imgid_t imgid, sqlite3_step(stmt); sqlite3_finalize(stmt); - dt_image_cache_set_change_timestamp(darktable.image_cache, imgid); + dt_image_cache_set_change_timestamp(imgid); dt_history_hash_write_from_history(imgid, DT_HISTORY_HASH_CURRENT); @@ -1023,10 +1021,10 @@ dt_image_orientation_t dt_image_get_orientation(const dt_imgid_t imgid) if(orientation == ORIENTATION_NULL) { - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); if(img) orientation = dt_image_orientation(img); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } return orientation; @@ -1089,21 +1087,13 @@ float dt_image_get_sensor_ratio(const dt_image_t *img) void dt_image_set_raw_aspect_ratio(const dt_imgid_t imgid) { - /* fetch image from cache */ - if(!darktable.image_cache) return; - - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); if(image) { /* set image aspect ratio */ - if(image->orientation < ORIENTATION_SWAP_XY) - image->aspect_ratio = (float )image->p_width / (float )(MAX(1, image->p_height)); - else - image->aspect_ratio = (float )image->p_height / (float )(MAX(1, image->p_width)); - /* store */ - dt_image_cache_write_release_info(darktable.image_cache, image, - DT_IMAGE_CACHE_SAFE, - "dt_image_set_raw_aspect_ratio"); + const int side = image->orientation < ORIENTATION_SWAP_XY ? image->p_height : image->p_width; + image->aspect_ratio = (float )image->p_height / (float )(MAX(1, side)); + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_SAFE, "dt_image_set_raw_aspect_ratio"); } } @@ -1114,14 +1104,14 @@ void dt_image_set_aspect_ratio_to(const dt_imgid_t imgid, if(aspect_ratio > .0f) { /* fetch image from cache */ - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); /* set image aspect ratio */ if(image) image->aspect_ratio = aspect_ratio; /* store but don't save xmp*/ - dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(image, DT_IMAGE_CACHE_RELAXED); if(image && raise && darktable.collection->params.sorts[DT_COLLECTION_SORT_ASPECT_RATIO]) dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, @@ -1137,42 +1127,40 @@ void dt_image_set_aspect_ratio_if_different(const dt_imgid_t imgid, if(aspect_ratio > .0f) { /* fetch image from cache */ - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *image = dt_image_cache_get(imgid, 'r'); + const gboolean new_aspect = image && !feqf(image->aspect_ratio, aspect_ratio, 0.02f); + dt_image_cache_read_release(image); /* set image aspect ratio */ - if(image && fabs(image->aspect_ratio - aspect_ratio) > 0.1) + if(new_aspect) { - dt_image_cache_read_release(darktable.image_cache, image); - dt_image_t *wimage = dt_image_cache_get(darktable.image_cache, imgid, 'w'); - wimage->aspect_ratio = aspect_ratio; - dt_image_cache_write_release(darktable.image_cache, wimage, DT_IMAGE_CACHE_RELAXED); - } - else - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_t *wimage = dt_image_cache_get(imgid, 'w'); + if(wimage) + wimage->aspect_ratio = aspect_ratio; + dt_image_cache_write_release(wimage, DT_IMAGE_CACHE_RELAXED); - if(image && raise && darktable.collection->params.sorts[DT_COLLECTION_SORT_ASPECT_RATIO]) - dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, + if(raise && darktable.collection->params.sorts[DT_COLLECTION_SORT_ASPECT_RATIO]) + dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, DT_COLLECTION_PROP_ASPECT_RATIO, g_list_prepend(NULL, GINT_TO_POINTER(imgid))); + } } } void dt_image_reset_aspect_ratio(const dt_imgid_t imgid, const gboolean raise) { /* fetch image from cache */ - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); /* set image aspect ratio */ if(image) { image->aspect_ratio = 0.f; /* store in db, but don't synch XMP */ - dt_image_cache_write_release_info(darktable.image_cache, image, - DT_IMAGE_CACHE_RELAXED, - "dt_image_reset_aspect_ratio"); + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_RELAXED, "dt_image_reset_aspect_ratio"); - if(raise && darktable.collection->params.sorts[DT_COLLECTION_SORT_ASPECT_RATIO]) - dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, + if(raise && darktable.collection->params.sorts[DT_COLLECTION_SORT_ASPECT_RATIO]) + dt_collection_update_query(darktable.collection, DT_COLLECTION_CHANGE_RELOAD, DT_COLLECTION_PROP_ASPECT_RATIO, g_list_prepend(NULL, GINT_TO_POINTER(imgid))); } @@ -1468,11 +1456,11 @@ static dt_imgid_t _image_duplicate_with_version(const dt_imgid_t imgid, DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_TAG_CHANGED); /* unset change timestamp */ - dt_image_cache_unset_change_timestamp(darktable.image_cache, newid); + dt_image_cache_unset_change_timestamp(newid); - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); const dt_imgid_t grpid = img ? img->group_id : NO_IMGID; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); if(darktable.gui && darktable.gui->grouping) { darktable.gui->expanded_group_id = grpid; @@ -1498,13 +1486,13 @@ void dt_image_remove(const dt_imgid_t imgid) if(dt_image_local_copy_reset(imgid)) return; sqlite3_stmt *stmt; - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); const dt_imgid_t old_group_id = img ? img->group_id : NO_IMGID; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); // make sure we remove from the cache first, or else the cache will // look for imgid in sql - dt_image_cache_remove(darktable.image_cache, imgid); + dt_image_cache_remove(imgid); const dt_imgid_t new_group_id = dt_grouping_remove_from_group(imgid); if(darktable.gui && darktable.gui->expanded_group_id == old_group_id) @@ -1691,20 +1679,20 @@ static int _image_read_duplicates(const uint32_t id, // is using DT_IMAGE_CACHE_SAFE and so will write the .XMP. But we must avoid // this has the xmp for the duplicate is read just below. newid = _image_duplicate_with_version_ext(id, version); - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, id, 'r'); + const dt_image_t *img = dt_image_cache_get(id, 'r'); grpid = img ? img->group_id : NO_IMGID; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } // make sure newid is not selected if(clear_selection) dt_selection_clear(darktable.selection); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, newid, 'w'); + dt_image_t *img = dt_image_cache_get(newid, 'w'); if(img) { dt_exif_xmp_read(img, xmpfilename, 0); img->version = version; } - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); if(dt_is_valid_imgid(grpid)) { @@ -1780,10 +1768,10 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, if(dt_is_valid_imgid(id)) { g_free(imgfname); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, id, 'w'); + dt_image_t *img = dt_image_cache_get(id, 'w'); if(img) img->flags &= ~DT_IMAGE_REMOVE; - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); _image_read_duplicates(id, normalized_filename, raise_signals); dt_image_synch_all_xmp(normalized_filename); g_free(ext); @@ -1869,7 +1857,7 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, if(sqlite3_step(stmt2) == SQLITE_ROW) { dt_imgid_t other_id = sqlite3_column_int(stmt2, 0); - dt_image_t *other_img = dt_image_cache_get(darktable.image_cache, other_id, 'w'); + dt_image_t *other_img = dt_image_cache_get(other_id, 'w'); gchar *other_basename = g_strdup(other_img->filename); gchar *cc3 = other_basename + strlen(other_img->filename); for(; *cc3 != '.' && cc3 > other_basename; cc3--) @@ -1881,9 +1869,7 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, if(!(dt_imageio_is_raw_by_extension(other_ext) || !strcmp(other_ext, "dng"))) { other_img->group_id = id; - dt_image_cache_write_release_info(darktable.image_cache, other_img, - DT_IMAGE_CACHE_SAFE, - "_image_import_internal"); + dt_image_cache_write_release_info(other_img, DT_IMAGE_CACHE_SAFE, "_image_import_internal"); sqlite3_stmt *stmt3; DT_DEBUG_SQLITE3_PREPARE_V2 (dt_database_get(darktable.db), @@ -1892,20 +1878,17 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, while(sqlite3_step(stmt3) == SQLITE_ROW) { other_id = sqlite3_column_int(stmt3, 0); - dt_image_t *group_img = dt_image_cache_get(darktable.image_cache, other_id, 'w'); + dt_image_t *group_img = dt_image_cache_get(other_id, 'w'); if(group_img) group_img->group_id = id; - dt_image_cache_write_release_info(darktable.image_cache, group_img, - DT_IMAGE_CACHE_SAFE, - "_image_import_internal"); + dt_image_cache_write_release_info(group_img, DT_IMAGE_CACHE_SAFE, "_image_import_internal"); } group_id = id; sqlite3_finalize(stmt3); } else { - dt_image_cache_write_release(darktable.image_cache, other_img, - DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(other_img, DT_IMAGE_CACHE_RELAXED); group_id = other_id; } g_free(other_ext); @@ -1949,7 +1932,7 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, // lock as shortly as possible: gboolean res = FALSE; - dt_image_t *img = dt_image_cache_get(darktable.image_cache, id, 'w'); + dt_image_t *img = dt_image_cache_get(id, 'w'); if(img) { img->group_id = group_id; @@ -1965,7 +1948,7 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, res = dt_exif_xmp_read(img, dtfilename, 0); } // write through to db, but not to xmp. - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); // read all sidecar files const int nb_xmp = _image_read_duplicates(id, normalized_filename, raise_signals); @@ -2300,14 +2283,14 @@ gboolean dt_image_rename(const dt_imgid_t imgid, while(dup_list) { const dt_imgid_t id = GPOINTER_TO_INT(dup_list->data); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, id, 'w'); + dt_image_t *img = dt_image_cache_get(id, 'w'); if(img) { img->film_id = filmid; if(newname) g_strlcpy(img->filename, newname, DT_MAX_FILENAME_LEN); } // write through to db, but not to xmp - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); dup_list = g_list_delete_link(dup_list, dup_list); // now also write xmp file dt_image_synch_xmp(id); @@ -2716,10 +2699,10 @@ gboolean dt_image_local_copy_set(const dt_imgid_t imgid) // update cache local copy flags, do this even if the local copy // already exists as we need to set the flags for duplicate - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); if(img) img->flags |= DT_IMAGE_LOCAL_COPY; - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); dt_control_queue_redraw_center(); return FALSE; @@ -2758,14 +2741,14 @@ gboolean dt_image_local_copy_reset(const dt_imgid_t imgid) gchar cachedir[PATH_MAX] = { 0 }; // check that a local copy exists, otherwise there is nothing to do - dt_image_t *imgr = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *imgr = dt_image_cache_get(imgid, 'r'); const gboolean local_copy_exists = imgr && ((imgr->flags & DT_IMAGE_LOCAL_COPY) == DT_IMAGE_LOCAL_COPY) ? TRUE : FALSE; - dt_image_cache_read_release(darktable.image_cache, imgr); + dt_image_cache_read_release(imgr); if(!local_copy_exists) return FALSE; @@ -2826,10 +2809,10 @@ gboolean dt_image_local_copy_reset(const dt_imgid_t imgid) // reach this point the local-copy flag is present and the file has been either removed // or is not present. - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); if(img) img->flags &= ~DT_IMAGE_LOCAL_COPY; - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); dt_control_queue_redraw_center(); @@ -2972,10 +2955,10 @@ void dt_image_get_datetime(const dt_imgid_t imgid, { if(!datetime) return; datetime[0] = '\0'; - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(imgid, 'r'); if(!cimg) return; dt_datetime_img_to_exif(datetime, DT_DATETIME_LENGTH, cimg); - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); } static void _datetime_undo_data_free(gpointer data) diff --git a/src/common/image.h b/src/common/image.h index 140c129c6588..2f821b1ecf51 100644 --- a/src/common/image.h +++ b/src/common/image.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2009-2024 darktable developers. + Copyright (C) 2009-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -300,7 +300,8 @@ typedef struct dt_image_t float aspect_ratio; // used by library - int32_t num, flags, film_id, version; + int32_t num, flags, version; + dt_filmid_t film_id; dt_imgid_t id; dt_imgid_t group_id; //timestamps diff --git a/src/common/image_cache.c b/src/common/image_cache.c index 3b20280e82b0..6533aa6bd328 100644 --- a/src/common/image_cache.c +++ b/src/common/image_cache.c @@ -205,10 +205,12 @@ static void _image_cache_deallocate(void *data, dt_cache_entry_t *entry) g_free(img->profile); g_list_free_full(img->dng_gain_maps, g_free); g_free(img); + entry->data = NULL; } -void dt_image_cache_init(dt_image_cache_t *cache) +void dt_image_cache_init() { + dt_image_cache_t *cache = darktable.image_cache = calloc(1, sizeof(dt_image_cache_t)); // the image cache does no serialization. // (unsafe. data should be in db/xmp, not in any other additional cache, // also, it should be relatively fast to get the image_t structs from sql.) @@ -224,29 +226,29 @@ void dt_image_cache_init(dt_image_cache_t *cache) dt_print(DT_DEBUG_CACHE, "[image_cache] has %d entries", num); } -void dt_image_cache_cleanup(dt_image_cache_t *cache) +void dt_image_cache_cleanup() { - dt_cache_cleanup(&cache->cache); -} - -void dt_image_cache_print(dt_image_cache_t *cache) -{ - dt_print(DT_DEBUG_ALWAYS, - "[image cache] fill %.2f/%.2f MB (%.2f%%)", + dt_image_cache_t *cache = darktable.image_cache; + if(!cache) return; + dt_print(DT_DEBUG_CACHE, + "[image cache cleaup report] fill %.2f/%.2f MB (%.2f%%)", cache->cache.cost / (1024.0 * 1024.0), cache->cache.cost_quota / (1024.0 * 1024.0), (float)cache->cache.cost / (float)cache->cache.cost_quota); + dt_cache_cleanup(&cache->cache); + free(cache); + darktable.image_cache = NULL; } -dt_image_t *dt_image_cache_get(dt_image_cache_t *cache, - const dt_imgid_t imgid, +dt_image_t *dt_image_cache_get(const dt_imgid_t imgid, const char mode) { + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!dt_is_valid_imgid(imgid)) - { - dt_print(DT_DEBUG_CACHE, "[dt_image_cache_get] failed as not a valid imgid=%d", imgid); return NULL; - } + dt_cache_entry_t *entry = dt_cache_get(&cache->cache, imgid, mode); ASAN_UNPOISON_MEMORY_REGION(entry->data, sizeof(dt_image_t)); dt_image_t *img = entry->data; @@ -254,10 +256,12 @@ dt_image_t *dt_image_cache_get(dt_image_cache_t *cache, return img; } -dt_image_t *dt_image_cache_testget(dt_image_cache_t *cache, - const dt_imgid_t imgid, +dt_image_t *dt_image_cache_testget(const dt_imgid_t imgid, const char mode) { + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!dt_is_valid_imgid(imgid)) { dt_print(DT_DEBUG_CACHE, "[dt_image_cache_testget] failed as not a valid imgid=%d", imgid); @@ -277,12 +281,12 @@ dt_image_t *dt_image_cache_testget(dt_image_cache_t *cache, } // drops the read lock on an image struct -void dt_image_cache_read_release(dt_image_cache_t *cache, - const dt_image_t *img) +void dt_image_cache_read_release(const dt_image_t *img) { if(!img || !dt_is_valid_imgid(img->id)) return; // just force the dt_image_t struct to make sure it has been locked before. - dt_cache_release(&cache->cache, img->cache_entry); + dt_image_cache_t *cache = darktable.image_cache; + if(cache) dt_cache_release(&cache->cache, img->cache_entry); } // drops the write privileges on an image struct. @@ -290,14 +294,16 @@ void dt_image_cache_read_release(dt_image_cache_t *cache, // a) mode == DT_IMAGE_CACHE_SAFE // b) sidecar writing is desired via conf setting // also to xmp sidecar files. -void dt_image_cache_write_release_info(dt_image_cache_t *cache, - dt_image_t *img, +void dt_image_cache_write_release_info(dt_image_t *img, const dt_image_cache_write_mode_t mode, const char *info) { if(!img) // nothing to release return; + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!dt_is_valid_imgid(img->id)) { dt_cache_release(&cache->cache, img->cache_entry); @@ -428,44 +434,45 @@ void dt_image_cache_write_release_info(dt_image_cache_t *cache, dt_cache_release(&cache->cache, img->cache_entry); } -void dt_image_cache_write_release(dt_image_cache_t *cache, - dt_image_t *img, - const dt_image_cache_write_mode_t mode) +void dt_image_cache_write_release(dt_image_t *img, const dt_image_cache_write_mode_t mode) { - dt_image_cache_write_release_info(cache, img, mode, NULL); + dt_image_cache_write_release_info(img, mode, NULL); } // remove the image from the cache -void dt_image_cache_remove(dt_image_cache_t *cache, - const dt_imgid_t imgid) +void dt_image_cache_remove(const dt_imgid_t imgid) { - dt_cache_remove(&cache->cache, imgid); + dt_image_cache_t *cache = darktable.image_cache; + if(cache) dt_cache_remove(&cache->cache, imgid); } /* set timestamps */ -void dt_image_cache_set_change_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid) +void dt_image_cache_set_change_timestamp(const dt_imgid_t imgid) { - if(!dt_is_valid_imgid(imgid)) return; + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + + if(!cache || !dt_is_valid_imgid(imgid)) return; dt_cache_entry_t *entry = dt_cache_get(&cache->cache, imgid, 'w'); if(!entry) return; ASAN_UNPOISON_MEMORY_REGION(entry->data, sizeof(dt_image_t)); dt_image_t *img = entry->data; img->cache_entry = entry; img->change_timestamp = dt_datetime_now_to_gtimespan(); - dt_image_cache_write_release(cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } -void dt_image_cache_set_change_timestamp_from_image(dt_image_cache_t *cache, - const dt_imgid_t imgid, +void dt_image_cache_set_change_timestamp_from_image(const dt_imgid_t imgid, const dt_imgid_t sourceid) { - if(!dt_is_valid_imgid(imgid) || !dt_is_valid_imgid(sourceid)) return; + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!cache || !dt_is_valid_imgid(imgid) || !dt_is_valid_imgid(sourceid)) return; // get source timestamp - const dt_image_t *simg = dt_image_cache_get(cache, sourceid, 'r'); + const dt_image_t *simg = dt_image_cache_get(sourceid, 'r'); const GTimeSpan change_timestamp = simg->change_timestamp; - dt_image_cache_read_release(cache, simg); + dt_image_cache_read_release(simg); dt_cache_entry_t *entry = dt_cache_get(&cache->cache, imgid, 'w'); if(!entry) return; @@ -473,46 +480,49 @@ void dt_image_cache_set_change_timestamp_from_image(dt_image_cache_t *cache, dt_image_t *img = entry->data; img->cache_entry = entry; img->change_timestamp = change_timestamp; - dt_image_cache_write_release(cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } -void dt_image_cache_unset_change_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid) +void dt_image_cache_unset_change_timestamp(const dt_imgid_t imgid) { - if(!dt_is_valid_imgid(imgid)) return; + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!cache || !dt_is_valid_imgid(imgid)) return; dt_cache_entry_t *entry = dt_cache_get(&cache->cache, imgid, 'w'); if(!entry) return; ASAN_UNPOISON_MEMORY_REGION(entry->data, sizeof(dt_image_t)); dt_image_t *img = entry->data; img->cache_entry = entry; img->change_timestamp = 0; - dt_image_cache_write_release(cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } -void dt_image_cache_set_export_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid) +void dt_image_cache_set_export_timestamp(const dt_imgid_t imgid) { - if(!dt_is_valid_imgid(imgid)) return; + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!cache || !dt_is_valid_imgid(imgid)) return; dt_cache_entry_t *entry = dt_cache_get(&cache->cache, imgid, 'w'); if(!entry) return; ASAN_UNPOISON_MEMORY_REGION(entry->data, sizeof(dt_image_t)); dt_image_t *img = entry->data; img->cache_entry = entry; img->export_timestamp = dt_datetime_now_to_gtimespan(); - dt_image_cache_write_release(cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } -void dt_image_cache_set_print_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid) +void dt_image_cache_set_print_timestamp(const dt_imgid_t imgid) { - if(!dt_is_valid_imgid(imgid)) return; + dt_image_cache_t *cache = darktable.image_cache; + assert(cache); + if(!cache || !dt_is_valid_imgid(imgid)) return; dt_cache_entry_t *entry = dt_cache_get(&cache->cache, imgid, 'w'); if(!entry) return; ASAN_UNPOISON_MEMORY_REGION(entry->data, sizeof(dt_image_t)); dt_image_t *img = entry->data; img->cache_entry = entry; img->print_timestamp = dt_datetime_now_to_gtimespan(); - dt_image_cache_write_release(cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } // clang-format off diff --git a/src/common/image_cache.h b/src/common/image_cache.h index 7caa19bde794..c0d1b9b47e48 100644 --- a/src/common/image_cache.h +++ b/src/common/image_cache.h @@ -42,9 +42,8 @@ typedef enum dt_image_cache_write_mode_t } dt_image_cache_write_mode_t; -void dt_image_cache_init(dt_image_cache_t *cache); -void dt_image_cache_cleanup(dt_image_cache_t *cache); -void dt_image_cache_print(dt_image_cache_t *cache); +void dt_image_cache_init(void); +void dt_image_cache_cleanup(void); // blocks until it gets the image struct with this id for reading. // also does the sql query if the image is not in cache atm. @@ -53,48 +52,33 @@ void dt_image_cache_print(dt_image_cache_t *cache); // cachelines to free up space if necessary. // if an entry is swapped out like this in the background, this is the latest // point where sql and xmp can be synched (unsafe setting). -dt_image_t *dt_image_cache_get(dt_image_cache_t *cache, - const dt_imgid_t imgid, - const char mode); +dt_image_t *dt_image_cache_get(const dt_imgid_t imgid, const char mode); // same as read_get, but doesn't block and returns NULL if the image // is currently unavailable. -dt_image_t *dt_image_cache_testget(dt_image_cache_t *cache, - const dt_imgid_t imgid, - const char mode); +dt_image_t *dt_image_cache_testget(const dt_imgid_t imgid, const char mode); // drops the read lock on an image struct -void dt_image_cache_read_release(dt_image_cache_t *cache, - const dt_image_t *img); +void dt_image_cache_read_release(const dt_image_t *img); // drops the write privileges on an image struct. // this triggers a write-through to sql, and if the setting // is present, also to xmp sidecar files (safe setting). -void dt_image_cache_write_release(dt_image_cache_t *cache, - dt_image_t *img, - const dt_image_cache_write_mode_t mode); +void dt_image_cache_write_release(dt_image_t *img, const dt_image_cache_write_mode_t mode); // As above with some additional information -void dt_image_cache_write_release_info(dt_image_cache_t *cache, - dt_image_t *img, +void dt_image_cache_write_release_info(dt_image_t *img, const dt_image_cache_write_mode_t mode, const char *info); // remove the image from the cache -void dt_image_cache_remove(dt_image_cache_t *cache, - const dt_imgid_t imgid); +void dt_image_cache_remove(const dt_imgid_t imgid); // register timestamps in cache -void dt_image_cache_set_change_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid); -void dt_image_cache_set_change_timestamp_from_image(dt_image_cache_t *cache, - const dt_imgid_t imgid, - const dt_imgid_t sourceid); -void dt_image_cache_unset_change_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid); -void dt_image_cache_set_export_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid); -void dt_image_cache_set_print_timestamp(dt_image_cache_t *cache, - const dt_imgid_t imgid); +void dt_image_cache_set_change_timestamp(const dt_imgid_t imgid); +void dt_image_cache_set_change_timestamp_from_image(const dt_imgid_t imgid, const dt_imgid_t sourceid); +void dt_image_cache_unset_change_timestamp(const dt_imgid_t imgid); +void dt_image_cache_set_export_timestamp(const dt_imgid_t imgid); +void dt_image_cache_set_print_timestamp(const dt_imgid_t imgid); #ifdef __cplusplus } // extern "C" diff --git a/src/common/mipmap_cache.c b/src/common/mipmap_cache.c index 4612b2db47e6..d5093f61d194 100644 --- a/src/common/mipmap_cache.c +++ b/src/common/mipmap_cache.c @@ -929,11 +929,11 @@ void dt_mipmap_cache_get_with_caller( // load the image: // make sure we access the r/w lock as shortly as possible! dt_image_t DT_ALIGNED_ARRAY buffered_image; - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(imgid, 'r'); buffered_image = *cimg; - // dt_image_t *img = dt_image_cache_write_get(darktable.image_cache, cimg); - // dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); - dt_image_cache_read_release(darktable.image_cache, cimg); + // dt_image_t *img = dt_image_cache_write_get(cimg); + // dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_read_release(cimg); char filename[PATH_MAX] = { 0 }; gboolean from_cache = TRUE; @@ -953,13 +953,13 @@ void dt_mipmap_cache_get_with_caller( if(ret == DT_IMAGEIO_OK) { // swap back new image data: - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); *img = buffered_image; img->load_status = DT_IMAGEIO_OK; // dt_print(DT_DEBUG_ALWAYS, "[mipmap read get] initializing full buffer img %u with %u %u -> %d %d (%p)", // imgid, data[0], data[1], img->width, img->height, data); // don't write xmp for this (we only changed db stuff): - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } else { @@ -976,10 +976,10 @@ void dt_mipmap_cache_get_with_caller( buf->color_space = DT_COLORSPACE_NONE; } // record the error code in the cache, so that later lookups know it actually failed - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); img->load_status = ret; // don't write xmp for this (we only changed db stuff): - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); } } else if(mip == DT_MIPMAP_F) @@ -1044,9 +1044,9 @@ void dt_mipmap_cache_get_with_caller( else if(dsc->width == 0 || dsc->height == 0) { // get the loading status of the image from the cache, so that we can assign an appropriate static image - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); - dt_imageio_retval_t ret = img->load_status; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_t *img = dt_image_cache_get(imgid, 'r'); + dt_imageio_retval_t ret = img ? img->load_status : DT_IMAGEIO_FILE_NOT_FOUND; + dt_image_cache_read_release(img); dt_print(DT_DEBUG_PIPE, "[mipmap cache get] got a zero-sized ID=%d mip %d!", imgid, mip); if(mip < DT_MIPMAP_F) { @@ -1280,7 +1280,7 @@ static void _init_f(dt_mipmap_buffer_t *mipmap_buf, // lock image after we have the buffer, we might need to lock the image struct for // writing during raw loading, to write to width/height. - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); dt_iop_roi_t roi_in; roi_in.x = roi_in.y = 0; @@ -1310,7 +1310,7 @@ static void _init_f(dt_mipmap_buffer_t *mipmap_buf, dt_control_log(_("unable to load image `%s'!"), image->filename); else dt_control_log(_("image '%s' not supported"), image->filename); - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); *width = *height = 0; *iscale = 0.0f; return; @@ -1371,7 +1371,7 @@ static void _init_f(dt_mipmap_buffer_t *mipmap_buf, *height = roi_out.height; *iscale = (float)image->width / (float)roi_out.width; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); } @@ -1437,11 +1437,11 @@ static void _init_8(uint8_t *buf, const gboolean altered = dt_image_altered(imgid); gboolean res = TRUE; - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(imgid, 'r'); // the orientation for this camera is not read correctly from exiv2, so we need // to go the full path (as the thumbnail will be flipped the wrong way round) const int incompatible = !strncmp(cimg->exif_maker, "Phase One", 9); - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); const char *min = dt_conf_get_string_const("plugins/lighttable/thumbnail_raw_min_level"); const dt_mipmap_size_t min_s = dt_mipmap_cache_get_min_mip_from_pref(min); @@ -1485,10 +1485,10 @@ static void _init_8(uint8_t *buf, if(!res) { // if the thumbnail is not large enough, we compute one - const dt_image_t *img2 = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img2 = dt_image_cache_get(imgid, 'r'); const int imgwd = img2->width; const int imght = img2->height; - dt_image_cache_read_release(darktable.image_cache, img2); + dt_image_cache_read_release(img2); if(thumb_width < wd && thumb_height < ht && thumb_width < imgwd - 4 diff --git a/src/common/ratings.c b/src/common/ratings.c index bf9fd8be984c..cecde2a9ee17 100644 --- a/src/common/ratings.c +++ b/src/common/ratings.c @@ -43,14 +43,14 @@ typedef struct dt_undo_ratings_t int dt_ratings_get(const dt_imgid_t imgid) { int stars = 0; - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *image = dt_image_cache_get(imgid, 'r'); if(image) { if(image->flags & DT_IMAGE_REJECTED) stars = DT_VIEW_REJECT; else stars = DT_VIEW_RATINGS_MASK & image->flags; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); } return stars; } @@ -58,7 +58,7 @@ int dt_ratings_get(const dt_imgid_t imgid) static void _ratings_apply_to_image(const dt_imgid_t imgid, const int rating) { int new_rating = rating; - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); if(image) { @@ -73,8 +73,7 @@ static void _ratings_apply_to_image(const dt_imgid_t imgid, const int rating) | (DT_VIEW_RATINGS_MASK & new_rating); } // synch through: - dt_image_cache_write_release_info(darktable.image_cache, image, - DT_IMAGE_CACHE_SAFE, "_ratings_apply_to_image"); + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_SAFE, "_ratings_apply_to_image"); } } @@ -278,11 +277,11 @@ static float _action_process_rating(gpointer target, const int id = GPOINTER_TO_INT(imgs->data); if(id == darktable.develop->preview_pipe->output_imgid) { - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, id, 'r'); + const dt_image_t *img = dt_image_cache_get(id, 'r'); if(img) { const int r = img->flags & DT_IMAGE_REJECTED ? DT_VIEW_REJECT : (img->flags & DT_VIEW_RATINGS_MASK); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); // translate in human readable value if(r == DT_VIEW_REJECT) diff --git a/src/common/selection.c b/src/common/selection.c index 576d3f9baae0..f9f0eb762a98 100644 --- a/src/common/selection.c +++ b/src/common/selection.c @@ -61,11 +61,11 @@ static void _selection_select(dt_selection_t *selection, { if(dt_is_valid_imgid(imgid)) { - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); if(image) { const dt_imgid_t img_group_id = image->group_id; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); gchar *query = NULL; if(!darktable.gui @@ -214,11 +214,11 @@ void dt_selection_deselect(dt_selection_t *selection, if(dt_is_valid_imgid(imgid)) { - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); if(image) { const dt_imgid_t img_group_id = image->group_id; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); gchar *query = NULL; if(!darktable.gui diff --git a/src/common/styles.c b/src/common/styles.c index b5933379dc1e..0147258e3182 100644 --- a/src/common/styles.c +++ b/src/common/styles.c @@ -966,7 +966,7 @@ void _styles_apply_to_image_ext(const char *name, if(dt_tag_new("darktable|changed", &tagid)) { dt_tag_attach(tagid, newimgid, FALSE, FALSE); - dt_image_cache_set_change_timestamp(darktable.image_cache, imgid); + dt_image_cache_set_change_timestamp(imgid); } /* if current image in develop reload history */ diff --git a/src/common/undo.c b/src/common/undo.c index 256afa4f0859..3c4fcb19073f 100644 --- a/src/common/undo.c +++ b/src/common/undo.c @@ -282,7 +282,7 @@ static void _undo_do_undo_redo(dt_undo_t *self, for(const GList *img = imgs; img; img = g_list_next(img)) { // udpate xmp is done via set_change_timestamp - dt_image_cache_set_change_timestamp(darktable.image_cache, GPOINTER_TO_INT(img->data)); + dt_image_cache_set_change_timestamp(GPOINTER_TO_INT(img->data)); while(img->next && img->data == img->next->data) imgs = g_list_delete_link(imgs, img->next); } diff --git a/src/common/variables.c b/src/common/variables.c index 58908cb0d65a..1d5ab637d10d 100644 --- a/src/common/variables.c +++ b/src/common/variables.c @@ -166,7 +166,7 @@ static void _init_expansion(dt_variables_params_t *params, gboolean iterate) { const dt_image_t *img = params->img ? (dt_image_t *)params->img - : dt_image_cache_get(darktable.image_cache, params->imgid, 'r'); + : dt_image_cache_get(params->imgid, 'r'); params->data->datetime = dt_datetime_img_to_gdatetime(img, darktable.utc_tz); if(params->data->datetime) @@ -224,7 +224,7 @@ static void _init_expansion(dt_variables_params_t *params, gboolean iterate) } } - if(params->img == NULL) dt_image_cache_read_release(darktable.image_cache, img); + if(params->img == NULL) dt_image_cache_read_release(img); } else { // session data @@ -588,11 +588,11 @@ static char *_get_base_value(dt_variables_params_t *params, char **variable) gchar buffer[1024]; const dt_image_t *img = params->img ? (dt_image_t *)params->img - : dt_image_cache_get(darktable.image_cache, params->imgid, 'r'); + : dt_image_cache_get(params->imgid, 'r'); dt_image_print_exif(img, buffer, sizeof(buffer)); if(params->img == NULL) - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); result = g_strdup(buffer); } else if(_has_prefix(variable, "VERSION.NAME") diff --git a/src/control/jobs/control_jobs.c b/src/control/jobs/control_jobs.c index e7319d368a66..9d8c7488ffcd 100644 --- a/src/control/jobs/control_jobs.c +++ b/src/control/jobs/control_jobs.c @@ -344,24 +344,27 @@ static int32_t _control_write_sidecar_files_job_run(dt_job_t *job) for(GList *t = params->index ; t && !_job_cancelled(job) ; t = g_list_next(t)) { const dt_imgid_t imgid = GPOINTER_TO_INT(t->data); - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, (int32_t)imgid, 'r'); - char dtfilename[PATH_MAX] = { 0 }; - dt_image_full_path(img->id, dtfilename, sizeof(dtfilename), NULL); - dt_image_path_append_version(img->id, dtfilename, sizeof(dtfilename)); - g_strlcat(dtfilename, ".xmp", sizeof(dtfilename)); - // write the sidecar, but ONLY if it is missing or its contents have changed - // this ensures that the sidecar is up-to-date with the database without - // modifying the file's timestamp if it is already up-to-date - if(!dt_exif_xmp_write(imgid, dtfilename, FALSE)) + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); + if(img) { - // put the timestamp into db. this can't be done in exif.cc - // since that code gets called for the copy exporter, too - DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); - sqlite3_step(stmt); - sqlite3_reset(stmt); - sqlite3_clear_bindings(stmt); + char dtfilename[PATH_MAX] = { 0 }; + dt_image_full_path(img->id, dtfilename, sizeof(dtfilename), NULL); + dt_image_path_append_version(img->id, dtfilename, sizeof(dtfilename)); + g_strlcat(dtfilename, ".xmp", sizeof(dtfilename)); + // write the sidecar, but ONLY if it is missing or its contents have changed + // this ensures that the sidecar is up-to-date with the database without + // modifying the file's timestamp if it is already up-to-date + if(!dt_exif_xmp_write(imgid, dtfilename, FALSE)) + { + // put the timestamp into db. this can't be done in exif.cc + // since that code gets called for the copy exporter, too + DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid); + sqlite3_step(stmt); + sqlite3_reset(stmt); + sqlite3_clear_bindings(stmt); + } + dt_image_cache_read_release(img); } - dt_image_cache_read_release(darktable.image_cache, img); const double fraction = ++count / (double)nb_imgs; _update_progress(job, fraction, &prev_time); } @@ -449,9 +452,9 @@ static int _control_merge_hdr_process(dt_imageio_module_data_t *datai, dt_control_merge_hdr_t *d = data->d; // just take a copy. also do it after blocking read, so filters will make sense. - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); const dt_image_t image = *img; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); if(!d->pixels) { @@ -730,8 +733,7 @@ static int32_t _control_duplicate_images_job_run(dt_job_t *job) dt_history_copy_and_paste_on_image(imgid, newimgid, FALSE, NULL, TRUE, TRUE, TRUE); // a duplicate should keep the change time stamp of the original - dt_image_cache_set_change_timestamp_from_image(darktable.image_cache, - newimgid, imgid); + dt_image_cache_set_change_timestamp_from_image(newimgid, imgid); _collection_update(&last_coll_update, &update_interval); } @@ -1396,13 +1398,13 @@ static int32_t _control_gpx_apply_job_run(dt_job_t *job) dt_imgid_t imgid = GPOINTER_TO_INT(t->data); /* get image */ - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(imgid, 'r'); if(!cimg) continue; GDateTime *exif_time = dt_datetime_img_to_gdatetime(cimg, tz_camera); /* release the lock */ - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); if(!exif_time) continue; GDateTime *utc_time = g_date_time_to_timezone(exif_time, darktable.utc_tz); g_date_time_unref(exif_time); @@ -1536,21 +1538,18 @@ static int32_t _control_refresh_exif_run(dt_job_t *job) char sourcefile[PATH_MAX]; dt_image_full_path(imgid, sourcefile, sizeof(sourcefile), &from_cache); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); if(img) { img->job_flags |= DT_IMAGE_JOB_NO_METADATA; // no metadata refresh, only EXIF dt_exif_read(img, sourcefile); - dt_image_cache_write_release_info(darktable.image_cache, img, - DT_IMAGE_CACHE_SAFE, - "dt_control_refresh_exif_run"); + dt_image_cache_write_release_info(img, DT_IMAGE_CACHE_SAFE, "dt_control_refresh_exif_run"); + DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_DEVELOP_IMAGE_CHANGED); } else dt_print(DT_DEBUG_ALWAYS, "[dt_control_refresh_exif_run] couldn't dt_image_cache_get for imgid %i", imgid); - - DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_DEVELOP_IMAGE_CHANGED); } else dt_print(DT_DEBUG_ALWAYS,"[dt_control_refresh_exif_run] illegal imgid %i", imgid); @@ -1890,7 +1889,7 @@ static int32_t _control_export_job_run(dt_job_t *job) dt_control_job_set_progress_message(job, message); // check if image still exists: - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); if(image) { char imgfilename[PATH_MAX] = { 0 }; @@ -1901,11 +1900,11 @@ static int32_t _control_export_job_run(dt_job_t *job) dt_control_log(_("image `%s' is currently unavailable"), image->filename); dt_print(DT_DEBUG_ALWAYS, "image `%s' is currently unavailable", imgfilename); // dt_image_remove(imgid); - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); } else { - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); if(mstorage->store(mstorage, sdata, imgid, mformat, fdata, num, total, settings->high_quality, settings->upscale, settings->export_masks, settings->icc_type, @@ -1921,7 +1920,7 @@ static int32_t _control_export_job_run(dt_job_t *job) if(dt_tag_attach(etagid, imgid, FALSE, FALSE)) tag_change = TRUE; /* register export timestamp in cache */ - dt_image_cache_set_export_timestamp(darktable.image_cache, imgid); + dt_image_cache_set_export_timestamp(imgid); } } } diff --git a/src/control/jobs/image_jobs.c b/src/control/jobs/image_jobs.c index 7150b02806a0..bc0000a2d509 100644 --- a/src/control/jobs/image_jobs.c +++ b/src/control/jobs/image_jobs.c @@ -36,7 +36,7 @@ static int32_t dt_image_load_job_run(dt_job_t *job) if(buf.buf && buf.height && buf.width) { - const double aspect_ratio = (double)buf.width / (double)buf.height; + const float aspect_ratio = (float)buf.width / (float)buf.height; dt_image_set_aspect_ratio_if_different(params->imgid, aspect_ratio, FALSE); } diff --git a/src/develop/develop.c b/src/develop/develop.c index c385d6171ee7..cdc6726c9572 100644 --- a/src/develop/develop.c +++ b/src/develop/develop.c @@ -519,9 +519,9 @@ static inline void _dt_dev_load_raw(dt_develop_t *dev, dt_mipmap_cache_release(darktable.mipmap_cache, &buf); dt_show_times(&start, "[dt_dev_load_raw] loading the image."); - const dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *image = dt_image_cache_get(imgid, 'r'); dev->image_storage = *image; - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); // dev->requested_id = (dev->image_storage.load_status == DT_IMAGEIO_OK) ? dev->image_storage.id : 0; dev->requested_id = dev->image_storage.id; @@ -1014,7 +1014,7 @@ static void _dev_add_history_item(dt_develop_t *dev, const gboolean tag_change = dt_tag_attach(tagid, imgid, FALSE, FALSE); /* register change timestamp in cache */ - dt_image_cache_set_change_timestamp(darktable.image_cache, imgid); + dt_image_cache_set_change_timestamp(imgid); // invalidate buffers and force redraw of darkroom if(!dev->history_postpone_invalidate @@ -1461,7 +1461,7 @@ static gboolean _dev_auto_apply_presets(dt_develop_t *dev) if(!dt_is_valid_imgid(imgid)) return FALSE; gboolean run = FALSE; - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); if(!(image->flags & DT_IMAGE_AUTO_PRESETS_APPLIED)) run = TRUE; const gboolean is_raw = dt_image_is_raw(image); @@ -1529,7 +1529,7 @@ static gboolean _dev_auto_apply_presets(dt_develop_t *dev) } } - dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(image, DT_IMAGE_CACHE_RELAXED); return FALSE; } @@ -1733,7 +1733,7 @@ static gboolean _dev_auto_apply_presets(dt_develop_t *dev) // make sure these end up in the image_cache; as the history is not correct right now // we don't write the sidecar here but later in dt_dev_read_history_ext - dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(image, DT_IMAGE_CACHE_RELAXED); return TRUE; } @@ -2345,13 +2345,10 @@ void dt_dev_read_history_ext(dt_develop_t *dev, dt_history_hash_write_from_history(imgid, flags); // As we have a proper history right now and this is first_run we // possibly write the xmp now - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); // depending on the xmp_writing mode we either us safe or relaxed const gboolean always = (dt_image_get_xmp_mode() == DT_WRITE_XMP_ALWAYS); - dt_image_cache_write_release - (darktable.image_cache, - image, - always ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(image, always ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED); } else if(legacy_params) { diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c index b9e36410cf90..14745019e22d 100644 --- a/src/dtgtk/thumbnail.c +++ b/src/dtgtk/thumbnail.c @@ -162,14 +162,14 @@ static void _image_update_group_tooltip(dt_thumbnail_t *thumb) tt = g_strdup_printf("\n\u2022 %s (%s)", _("current"), _("leader")); else { - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, thumb->groupid, 'r'); + const dt_image_t *img = dt_image_cache_get(thumb->groupid, 'r'); if(img) { tt = g_strdup_printf ("%s\n\u2022 %s (%s)", _("\nclick here to set this image as group leader\n"), img->filename, _("leader")); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } } @@ -239,7 +239,7 @@ static void _image_get_infos(dt_thumbnail_t *thumb) const int old_rating = thumb->rating; thumb->rating = 0; - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, thumb->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(thumb->imgid, 'r'); if(img) { thumb->has_localcopy = (img->flags & DT_IMAGE_LOCAL_COPY); @@ -252,7 +252,7 @@ static void _image_get_infos(dt_thumbnail_t *thumb) thumb->groupid = img->group_id; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } // if the rating as changed, update the rejected if(old_rating != thumb->rating) @@ -477,11 +477,11 @@ static void _get_dimensions_for_img_to_fit(const dt_thumbnail_t *thumb, { // let's try with the aspect_ratio store in image structure, even // if it's less accurate - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, thumb->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(thumb->imgid, 'r'); if(img) { ar = img->aspect_ratio; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } } @@ -518,7 +518,7 @@ static void _get_dimensions_for_zoomed_img(dt_thumbnail_t *thumb, // the max zoom, but also to ensure that final_width and height are // available. const float zoom_100 = dt_thumbnail_get_zoom100(thumb); - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, thumb->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(thumb->imgid, 'r'); if(img) { if(img->final_width > 0 && img->final_height > 0) @@ -526,7 +526,7 @@ static void _get_dimensions_for_zoomed_img(dt_thumbnail_t *thumb, iw = img->final_width; ih = img->final_height; } - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } // scale first to "img to fit", then apply the zoom ratio to get the @@ -1684,7 +1684,7 @@ dt_thumbnail_t *dt_thumbnail_new(const int width, thumb->expose_again_timeout_id = 0; // we read and cache all the infos from dt_image_t that we need - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, thumb->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(thumb->imgid, 'r'); if(img) { thumb->filename = g_strdup(img->filename); @@ -1693,7 +1693,7 @@ dt_thumbnail_t *dt_thumbnail_new(const int width, thumb->has_audio = (img->flags & DT_IMAGE_HAS_WAV); thumb->has_localcopy = (img->flags & DT_IMAGE_LOCAL_COPY); } - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } if(thumb->over == DT_THUMBNAIL_OVERLAYS_ALWAYS_EXTENDED || thumb->over == DT_THUMBNAIL_OVERLAYS_HOVER_EXTENDED @@ -2307,7 +2307,7 @@ float dt_thumbnail_get_zoom_ratio(dt_thumbnail_t *thumb) // force the reload of image infos void dt_thumbnail_reload_infos(dt_thumbnail_t *thumb) { - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, thumb->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(thumb->imgid, 'r'); if(img) { if(thumb->over != DT_THUMBNAIL_OVERLAYS_NONE) @@ -2317,7 +2317,7 @@ void dt_thumbnail_reload_infos(dt_thumbnail_t *thumb) thumb->has_localcopy = (img->flags & DT_IMAGE_LOCAL_COPY); } - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } if(thumb->over == DT_THUMBNAIL_OVERLAYS_ALWAYS_EXTENDED || thumb->over == DT_THUMBNAIL_OVERLAYS_HOVER_EXTENDED diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index 5ed06f60a50b..39faec8d9ec7 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -2913,8 +2913,7 @@ static void _accel_duplicate(dt_action_t *action) dt_history_copy_and_paste_on_image(sourceid, newimgid, FALSE, NULL, TRUE, TRUE, TRUE); // a duplicate should keep the change time stamp of the original - dt_image_cache_set_change_timestamp_from_image(darktable.image_cache, - newimgid, sourceid); + dt_image_cache_set_change_timestamp_from_image(newimgid, sourceid); dt_undo_end_group(darktable.undo); diff --git a/src/imageio/storage/disk.c b/src/imageio/storage/disk.c index a06fd9fd80dd..cf9cbb9c0ae5 100644 --- a/src/imageio/storage/disk.c +++ b/src/imageio/storage/disk.c @@ -461,10 +461,11 @@ int store(dt_imageio_module_storage_t *self, if(g_file_test(filename, G_FILE_TEST_EXISTS)) { // get the image data - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); - const GTimeSpan change_timestamp = img->change_timestamp; - const GTimeSpan export_timestamp = img->export_timestamp; - dt_image_cache_read_release(darktable.image_cache, img); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); + const GTimeSpan change_timestamp = img ? img->change_timestamp : 0; + const GTimeSpan export_timestamp = img ? img->export_timestamp : 0; + + dt_image_cache_read_release(img); // check if the export timestamp in the database is more recent than the change // date, if yes skip the image diff --git a/src/imageio/storage/email.c b/src/imageio/storage/email.c index ab52993a9154..8cb98c69ab37 100644 --- a/src/imageio/storage/email.c +++ b/src/imageio/storage/email.c @@ -287,10 +287,9 @@ void finalize_store(dt_imageio_module_storage_t *self, m_fd[index].lpFileType = NULL; m_fd[index].nPosition = (ULONG) -1; - const dt_image_t *img = - dt_image_cache_get(darktable.image_cache, attachment->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(attachment->imgid, 'r'); dt_image_print_exif(img, exif, sizeof(exif)); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); gchar *imgbody = g_strdup_printf(imageBodyFormat, filename, exif); if(body != NULL) @@ -311,7 +310,7 @@ void finalize_store(dt_imageio_module_storage_t *self, MapiMessage m_msg; ZeroMemory(&m_msg, sizeof (m_msg)); - m_msg.lpszSubject = (LPSTR) _convert_to_widechar(CP_UTF8, + m_msg.lpszSubject = (LPSTR) _convert_to_widechar(CP_UTF8, _("images exported from darktable")); m_msg.lpszNoteText = (LPSTR) _convert_to_widechar(CP_ACP, body); @@ -411,10 +410,9 @@ void finalize_store(dt_imageio_module_storage_t *self, gchar exif[256] = { 0 }; _email_attachment_t *attachment = (_email_attachment_t *)iter->data; gchar *filename = g_path_get_basename(attachment->file); - const dt_image_t *img = - dt_image_cache_get(darktable.image_cache, attachment->imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(attachment->imgid, 'r'); dt_image_print_exif(img, exif, sizeof(exif)); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); gchar *imgbody = g_strdup_printf(imageBodyFormat, filename, exif); if(body != NULL) diff --git a/src/imageio/storage/piwigo.c b/src/imageio/storage/piwigo.c index 37cd1a4a93c6..88e8e48840c6 100644 --- a/src/imageio/storage/piwigo.c +++ b/src/imageio/storage/piwigo.c @@ -1268,7 +1268,7 @@ int store(dt_imageio_module_storage_t *self, char *description = NULL; char *author = NULL; - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *img = dt_image_cache_get(imgid, 'r'); char *filename = _get_filename(img, format, fdata); @@ -1323,7 +1323,7 @@ int store(dt_imageio_module_storage_t *self, g_free(filename); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); if(dt_imageio_export(imgid, fname, format, fdata, high_quality, upscale, TRUE, export_masks, icc_type, icc_filename, diff --git a/src/iop/colorin.c b/src/iop/colorin.c index 790ef78381de..f6fc2153f89f 100644 --- a/src/iop/colorin.c +++ b/src/iop/colorin.c @@ -1374,7 +1374,7 @@ void commit_params(dt_iop_module_t *self, if(type == DT_COLORSPACE_EMBEDDED_ICC) { // embedded color profile - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, pipe->image.id, 'r'); + const dt_image_t *cimg = dt_image_cache_get(pipe->image.id, 'r'); if(cimg == NULL || cimg->profile == NULL) type = DT_COLORSPACE_EMBEDDED_MATRIX; else @@ -1382,13 +1382,13 @@ void commit_params(dt_iop_module_t *self, d->input = dt_colorspaces_get_rgb_profile_from_mem(cimg->profile, cimg->profile_size); d->clear_input = TRUE; } - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); } if(type == DT_COLORSPACE_EMBEDDED_MATRIX) { // embedded matrix, hopefully D65 - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, pipe->image.id, 'r'); - if(!dt_is_valid_colormatrix(cimg->d65_color_matrix[0])) + const dt_image_t *cimg = dt_image_cache_get(pipe->image.id, 'r'); + if(!cimg || !dt_is_valid_colormatrix(cimg->d65_color_matrix[0])) type = DT_COLORSPACE_STANDARD_MATRIX; else { @@ -1396,7 +1396,7 @@ void commit_params(dt_iop_module_t *self, ((float(*)[3])cimg->d65_color_matrix); d->clear_input = TRUE; } - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); } if(type == DT_COLORSPACE_STANDARD_MATRIX) { @@ -1708,8 +1708,7 @@ void reload_defaults(dt_iop_module_t *self) // some file formats like jpeg can have an embedded color profile // currently we only support jpeg, j2k, tiff, png, avif, and heif - dt_image_t *img = dt_image_cache_get(darktable.image_cache, - self->dev->image_storage.id, 'w'); + dt_image_t *img = dt_image_cache_get(self->dev->image_storage.id, 'w'); if(!img->profile) { @@ -1911,7 +1910,7 @@ void reload_defaults(dt_iop_module_t *self) else // no ICC tag nor colorprofile was found - ICC spec says untagged files are sRGB d->type = DT_COLORSPACE_SRGB; - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); update_profile_list(self); } @@ -1930,9 +1929,8 @@ static void update_profile_list(dt_iop_module_t *self) int pos = -1; // some file formats like jpeg can have an embedded color profile // currently we only support jpeg, j2k, tiff and png - const dt_image_t *cimg = - dt_image_cache_get(darktable.image_cache, self->dev->image_storage.id, 'r'); - if(cimg->profile) + const dt_image_t *cimg = dt_image_cache_get(self->dev->image_storage.id, 'r'); + if(cimg && cimg->profile) { dt_colorspaces_color_profile_t *prof = calloc(1, sizeof(dt_colorspaces_color_profile_t)); g_strlcpy(prof->name, dt_colorspaces_get_name(DT_COLORSPACE_EMBEDDED_ICC, ""), @@ -1941,7 +1939,7 @@ static void update_profile_list(dt_iop_module_t *self) g->image_profiles = g_list_append(g->image_profiles, prof); prof->in_pos = ++pos; } - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); // use the matrix embedded in some DNGs and EXRs if(dt_is_valid_colormatrix(self->dev->image_storage.d65_color_matrix[0])) { diff --git a/src/iop/demosaic.c b/src/iop/demosaic.c index 4ddb6a41c9c0..bbc810a0a6b5 100644 --- a/src/iop/demosaic.c +++ b/src/iop/demosaic.c @@ -1247,7 +1247,7 @@ void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous) gtk_widget_set_visible(g->dual_thrs, isdual); gtk_widget_set_visible(g->lmmse_refine, islmmse); - dt_image_t *img = dt_image_cache_get(darktable.image_cache, self->dev->image_storage.id, 'w'); + dt_image_t *img = dt_image_cache_get(self->dev->image_storage.id, 'w'); int mono_changed = img->flags & DT_IMAGE_MONOCHROME_BAYER; if(p->demosaicing_method == DT_IOP_DEMOSAIC_PASSTHROUGH_MONOCHROME || p->demosaicing_method == DT_IOP_DEMOSAIC_PASSTHR_MONOX) @@ -1256,7 +1256,7 @@ void gui_changed(dt_iop_module_t *self, GtkWidget *w, void *previous) img->flags &= ~DT_IMAGE_MONOCHROME_BAYER; const int mask_bw = dt_image_monochrome_flags(img); mono_changed ^= img->flags & DT_IMAGE_MONOCHROME_BAYER; - dt_image_cache_write_release(darktable.image_cache, img, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(img, DT_IMAGE_CACHE_RELAXED); if(mono_changed) { diff --git a/src/iop/exposure.c b/src/iop/exposure.c index 3912ee91b717..94f1548b07b8 100644 --- a/src/iop/exposure.c +++ b/src/iop/exposure.c @@ -343,12 +343,11 @@ static void _deflicker_prepare_histogram(dt_iop_module_t *self, uint32_t **histogram, dt_dev_histogram_stats_t *histogram_stats) { - const dt_image_t *img = - dt_image_cache_get(darktable.image_cache, self->dev->image_storage.id, 'r'); + const dt_image_t *img = dt_image_cache_get(self->dev->image_storage.id, 'r'); dt_image_t image = *img; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); - if(image.buf_dsc.channels != 1 || image.buf_dsc.datatype != TYPE_UINT16) return; + if(!img || image.buf_dsc.channels != 1 || image.buf_dsc.datatype != TYPE_UINT16) return; dt_mipmap_buffer_t buf; dt_mipmap_cache_get(darktable.mipmap_cache, &buf, diff --git a/src/iop/rawprepare.c b/src/iop/rawprepare.c index 90d074dd13b2..68dc22ce15d6 100644 --- a/src/iop/rawprepare.c +++ b/src/iop/rawprepare.c @@ -627,10 +627,10 @@ static gboolean _image_set_rawcrops(dt_iop_module_t *self, // we update p_width & height both in the image_storage for fast access within the pipeline // and the database so we can access that also via dt_image_cache_get() - dt_image_t *image = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *image = dt_image_cache_get(imgid, 'w'); image->p_width = img->p_width = img->width - (cropvalid ? left + right : 0); image->p_height = img->p_height = img->height - (cropvalid ? top + bottom : 0); - dt_image_cache_write_release(darktable.image_cache, image, DT_IMAGE_CACHE_RELAXED); + dt_image_cache_write_release(image, DT_IMAGE_CACHE_RELAXED); return TRUE; } diff --git a/src/libs/copy_history.c b/src/libs/copy_history.c index d58eea28cfd7..a0f64752e7cc 100644 --- a/src/libs/copy_history.c +++ b/src/libs/copy_history.c @@ -126,7 +126,7 @@ static void load_button_clicked(GtkWidget *widget, dt_lib_module_t *self) { //single image to load xmp to, assume we want to load from same dir const dt_imgid_t imgid = GPOINTER_TO_INT(imgs->data); - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); if(img && img->film_id != -1) { char pathname[PATH_MAX] = { 0 }; @@ -140,7 +140,7 @@ static void load_button_clicked(GtkWidget *widget, dt_lib_module_t *self) dt_conf_get_folder_to_file_chooser("ui_last/import_path", GTK_FILE_CHOOSER(filechooser)); } - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } else { diff --git a/src/libs/geotagging.c b/src/libs/geotagging.c index ef60d050704f..700720a84e6f 100644 --- a/src/libs/geotagging.c +++ b/src/libs/geotagging.c @@ -785,10 +785,10 @@ static void _refresh_selected_images_datetime(dt_lib_module_t *self) for(GList *i = d->imgs; i; i = g_list_next(i)) { dt_sel_img_t *img = i->data; - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, img->imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(img->imgid, 'r'); if(!cimg) continue; dt_datetime_img_to_exif(img->dt, sizeof(img->dt), cimg); - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); } } @@ -926,11 +926,11 @@ static void _setup_selected_images_list(dt_lib_module_t *self) while(sqlite3_step(stmt) == SQLITE_ROW) { const dt_imgid_t imgid = sqlite3_column_int(stmt, 0); - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *cimg = dt_image_cache_get(imgid, 'r'); char dt[DT_DATETIME_LENGTH]; if(!cimg) continue; dt_datetime_img_to_exif(dt, sizeof(dt), cimg); - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); dt_sel_img_t *img = g_malloc0(sizeof(dt_sel_img_t)); if(!img) continue; diff --git a/src/libs/histogram.c b/src/libs/histogram.c index a0130b331846..0ea60ff49b42 100644 --- a/src/libs/histogram.c +++ b/src/libs/histogram.c @@ -2046,14 +2046,14 @@ static void _update_color_harmony_gui(dt_lib_module_t *self) const dt_imgid_t imgid = darktable.develop->image_storage.id; - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); dt_color_harmony_init(&d->harmony_guide); if(img) { memcpy(&d->harmony_guide, &img->color_harmony_guide, sizeof(dt_color_harmony_guide_t)); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } // restore rotation/width default @@ -2119,15 +2119,13 @@ static void _color_harmony_changed_record(dt_lib_histogram_t *d) const dt_imgid_t imgid = darktable.develop->image_storage.id; - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'w'); + dt_image_t *img = dt_image_cache_get(imgid, 'w'); memcpy(&img->color_harmony_guide, &d->harmony_guide, sizeof(dt_color_harmony_guide_t)); - dt_image_cache_write_release_info - (darktable.image_cache, img, - DT_IMAGE_CACHE_SAFE, "histogram color_harmony_changed_record"); + dt_image_cache_write_release_info(img, DT_IMAGE_CACHE_SAFE, "histogram color_harmony_changed_record"); } static gboolean _color_harmony_clicked(GtkWidget *button, diff --git a/src/libs/image.c b/src/libs/image.c index 954cbff12efc..bd356eb28219 100644 --- a/src/libs/image.c +++ b/src/libs/image.c @@ -241,10 +241,10 @@ void gui_update(dt_lib_module_t *self) const dt_imgid_t imgid = dt_act_on_get_main_image(); if(dt_is_valid_imgid(imgid)) { - dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + dt_image_t *img = dt_image_cache_get(imgid, 'r'); const gboolean is_bw = (dt_image_monochrome_flags(img) != 0); const int img_group_id = img->group_id; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); gtk_widget_set_sensitive(GTK_WIDGET(d->set_monochrome_button), !is_bw); gtk_widget_set_sensitive(GTK_WIDGET(d->set_color_button), is_bw); sqlite3_stmt *stmt; diff --git a/src/libs/lib.c b/src/libs/lib.c index 629c2b4ff5c8..39bb6325a60a 100644 --- a/src/libs/lib.c +++ b/src/libs/lib.c @@ -71,7 +71,7 @@ gboolean dt_lib_is_visible_in_view(dt_lib_module_t *module, } /** calls module->cleanup and closes the dl connection. */ -static void dt_lib_unload_module(dt_lib_module_t *module); +static void _lib_unload_module(dt_lib_module_t *module); gchar *dt_lib_get_active_preset_name(dt_lib_module_info_t *minfo) { @@ -880,7 +880,7 @@ static void dt_lib_init_module(void *m) } } -void dt_lib_unload_module(dt_lib_module_t *module) +void _lib_unload_module(dt_lib_module_t *module) { if(module->module) g_module_close(module->module); @@ -1375,7 +1375,7 @@ void dt_lib_cleanup(dt_lib_t *lib) module->gui_cleanup(module); module->data = NULL; } - dt_lib_unload_module(module); + _lib_unload_module(module); free(module); } lib->plugins = g_list_delete_link(lib->plugins, lib->plugins); diff --git a/src/libs/live_view.c b/src/libs/live_view.c index 104ad69c28bf..b4682e83cb48 100644 --- a/src/libs/live_view.c +++ b/src/libs/live_view.c @@ -458,9 +458,9 @@ void gui_post_expose(dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t if(dt_is_valid_imgid(imgid)) { cairo_save(cr); - const dt_image_t *img = dt_image_cache_testget(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_testget(imgid, 'r'); // if the user points at this image, we really want it: - if(!img) img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + if(!img) img = dt_image_cache_get(imgid, 'r'); const float imgwd = 0.97f; dt_mipmap_buffer_t buf; @@ -544,7 +544,7 @@ void gui_post_expose(dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t } cairo_restore(cr); if(buf.buf) dt_mipmap_cache_release(darktable.mipmap_cache, &buf); - if(img) dt_image_cache_read_release(darktable.image_cache, img); + if(img) dt_image_cache_read_release(img); // ON CANVAS CONTROLS if(use_splitline) diff --git a/src/libs/metadata_view.c b/src/libs/metadata_view.c index 8d67050c3e58..6f594959b6bc 100644 --- a/src/libs/metadata_view.c +++ b/src/libs/metadata_view.c @@ -661,13 +661,13 @@ void gui_update(dt_lib_module_t *self) g_free(images); dt_imgid_t img_id = mouse_over_id; - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, img_id, 'r'); + const dt_image_t *img = dt_image_cache_get(img_id, 'r'); if(!img) goto fill_minuses; if(img->film_id == -1) { - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); goto fill_minuses; } @@ -1084,7 +1084,7 @@ void gui_update(dt_lib_module_t *self) _metadata_update_value(md, text, self); } } - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); g_free(skip); @@ -1130,9 +1130,9 @@ static void _jump_to() if(dt_is_valid_imgid(imgid)) { char path[512]; - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); dt_image_film_roll_directory(img, path, sizeof(path)); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); char collect[1024]; snprintf(collect, sizeof(collect), "1:0:0:%s$", path); dt_collection_deserialize(collect, FALSE); diff --git a/src/libs/modulegroups.c b/src/libs/modulegroups.c index bf5a17d78e09..2595be2f73c7 100644 --- a/src/libs/modulegroups.c +++ b/src/libs/modulegroups.c @@ -2735,8 +2735,7 @@ static void _dt_dev_image_changed_callback(gpointer instance, dt_develop_t *dev = darktable.develop; if(!dev || !dt_is_valid_imgid(dev->image_storage.id)) return; - const dt_image_t *image = - dt_image_cache_get(darktable.image_cache, dev->image_storage.id, 'r'); + const dt_image_t *image = dt_image_cache_get(dev->image_storage.id, 'r'); if(!image) return; @@ -2787,7 +2786,7 @@ static void _dt_dev_image_changed_callback(gpointer instance, DT_DEBUG_SQLITE3_BIND_INT(stmt, 11, iformat); DT_DEBUG_SQLITE3_BIND_INT(stmt, 12, excluded); - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); if(sqlite3_step(stmt) == SQLITE_ROW) { diff --git a/src/libs/print_settings.c b/src/libs/print_settings.c index a3d5a175d1d5..dfd01b23895a 100644 --- a/src/libs/print_settings.c +++ b/src/libs/print_settings.c @@ -608,14 +608,15 @@ static int _print_job_run(dt_job_t *job) snprintf (tag, sizeof(tag), "darktable|printed|%s", params->prt.printer.name); dt_tag_new(tag, &tagid); - for(int k=0; kimgs.count; k++) + for(int k=0; k < params->imgs.count; k++) { if(dt_is_valid_imgid(params->imgs.box[k].imgid)) + { if(dt_tag_attach(tagid, params->imgs.box[k].imgid, FALSE, FALSE)) DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_TAG_CHANGED); - - /* register print timestamp in cache */ - dt_image_cache_set_print_timestamp(darktable.image_cache, params->imgs.box[k].imgid); + /* register print timestamp in cache */ + dt_image_cache_set_print_timestamp(params->imgs.box[k].imgid); + } } return 0; @@ -746,7 +747,7 @@ static void _print_button_clicked(GtkWidget *widget, dt_lib_module_t *self) } else { - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); if(!img) { // in this case no need to release from cache what we couldn't get @@ -755,7 +756,7 @@ static void _print_button_clicked(GtkWidget *widget, dt_lib_module_t *self) return; } params->job_title = g_strdup(img->filename); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); } // FIXME: ellipsize title/printer as the export completed message is ellipsized gchar *message = g_strdup_printf(_("processing `%s' for `%s'"), diff --git a/src/lua/image.c b/src/lua/image.c index 85be77cc01ed..6a72b46ef84d 100644 --- a/src/lua/image.c +++ b/src/lua/image.c @@ -45,25 +45,24 @@ static const dt_image_t *checkreadimage(lua_State *L, int index) { dt_lua_image_t imgid; luaA_to(L, dt_lua_image_t, &imgid, index); - return dt_image_cache_get(darktable.image_cache, imgid, 'r'); + return dt_image_cache_get(imgid, 'r'); } static void releasereadimage(lua_State *L, const dt_image_t *image) { - dt_image_cache_read_release(darktable.image_cache, image); + dt_image_cache_read_release(image); } static dt_image_t *checkwriteimage(lua_State *L, int index) { dt_lua_image_t imgid; luaA_to(L, dt_lua_image_t, &imgid, index); - return dt_image_cache_get(darktable.image_cache, imgid, 'w'); + return dt_image_cache_get(imgid, 'w'); } static void releasewriteimage(lua_State *L, dt_image_t *image) { - dt_image_cache_write_release_info(darktable.image_cache, image, - DT_IMAGE_CACHE_SAFE, "lua releasewriteimage"); + dt_image_cache_write_release_info(image, DT_IMAGE_CACHE_SAFE, "lua releasewriteimage"); } void dt_lua_image_push(lua_State *L, const dt_imgid_t imgid) @@ -444,9 +443,9 @@ int group_with(lua_State *L) dt_lua_image_t second_image; luaA_to(L, dt_lua_image_t, &second_image, 2); - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, second_image, 'r'); + const dt_image_t *cimg = dt_image_cache_get(second_image, 'r'); const dt_imgid_t group_id = cimg->group_id; - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); dt_grouping_add_to_group(group_id, first_image); return 0; @@ -465,9 +464,9 @@ int get_group(lua_State *L) { dt_lua_image_t first_image; luaA_to(L, dt_lua_image_t, &first_image, 1); - const dt_image_t *cimg = dt_image_cache_get(darktable.image_cache, first_image, 'r'); + const dt_image_t *cimg = dt_image_cache_get(first_image, 'r'); const dt_imgid_t group_id = cimg->group_id; - dt_image_cache_read_release(darktable.image_cache, cimg); + dt_image_cache_read_release(cimg); sqlite3_stmt *stmt; DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "SELECT id FROM main.images WHERE group_id = ?1", -1, diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 33e114303441..82b93fa2a2c0 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -544,9 +544,9 @@ void expose(dt_view_t *self, { gchar *load_txt; float fontsize; - dt_image_t *img = dt_image_cache_get(darktable.image_cache, dev->image_storage.id, 'r');; + dt_image_t *img = dt_image_cache_get(dev->image_storage.id, 'r');; dt_imageio_retval_t status = img->load_status; - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); if(dev->image_invalid_cnt) { @@ -851,7 +851,7 @@ gboolean try_enter(dt_view_t *self) } // this loads the image from db if needed: - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); // get image and check if it has been deleted from disk first! char imgfilename[PATH_MAX] = { 0 }; @@ -860,7 +860,7 @@ gboolean try_enter(dt_view_t *self) if(!g_file_test(imgfilename, G_FILE_TEST_IS_REGULAR)) { dt_control_log(_("image `%s' is currently unavailable"), img->filename); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); return TRUE; } else if(img->load_status != DT_IMAGEIO_OK) @@ -895,11 +895,11 @@ gboolean try_enter(dt_view_t *self) break; } dt_control_log(_("image `%s' could not be loaded\n%s"), img->filename, reason); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); return TRUE; } // and drop the lock again. - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); darktable.develop->image_storage.id = imgid; dt_dev_reset_chroma(darktable.develop); diff --git a/src/views/print.c b/src/views/print.c index 35b12a7a19a3..7626b2e4296b 100644 --- a/src/views/print.c +++ b/src/views/print.c @@ -320,20 +320,20 @@ gboolean try_enter(dt_view_t *self) } // this loads the image from db if needed: - const dt_image_t *img = dt_image_cache_get(darktable.image_cache, imgid, 'r'); + const dt_image_t *img = dt_image_cache_get(imgid, 'r'); // get image and check if it has been deleted from disk first! char imgfilename[PATH_MAX] = { 0 }; gboolean from_cache = TRUE; - dt_image_full_path(img->id, imgfilename, sizeof(imgfilename), &from_cache); - if(!g_file_test(imgfilename, G_FILE_TEST_IS_REGULAR)) + if(img) dt_image_full_path(img->id, imgfilename, sizeof(imgfilename), &from_cache); + if(!img || !g_file_test(imgfilename, G_FILE_TEST_IS_REGULAR)) { dt_control_log(_("image `%s' is currently unavailable"), img->filename); - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); return 1; } // and drop the lock again. - dt_image_cache_read_release(darktable.image_cache, img); + dt_image_cache_read_release(img); // we need to setup the selected image prt->imgs->imgid_to_load = imgid; From 8bd2f96f6b7a54141688139204bfd52f5402cf30 Mon Sep 17 00:00:00 2001 From: Hanno Schwalm Date: Sat, 15 Feb 2025 13:58:07 +0100 Subject: [PATCH 3/3] Hide mipmap cache implementation details 1. All mipmap functions don't require the cache location pointer any longer for readability 2. some asserts added for debug builds 3. Allocation and free of mipmap cache memory done inside the init and cleanup functions 4. Some leading underscore fixes for static functions --- src/common/cache.c | 30 ++--- src/common/darktable.c | 14 +-- src/common/film.c | 2 +- src/common/history.c | 6 +- src/common/image.c | 25 ++-- src/common/mipmap_cache.c | 218 +++++++++++++++++++--------------- src/common/mipmap_cache.h | 33 +++-- src/common/styles.c | 2 +- src/control/crawler.c | 6 +- src/control/jobs/image_jobs.c | 16 +-- src/develop/develop.c | 14 +-- src/dtgtk/culling.c | 8 +- src/dtgtk/thumbnail.c | 5 +- src/dtgtk/thumbtable.c | 10 +- src/generate-cache/main.c | 6 +- src/imageio/imageio.c | 7 +- src/iop/demosaic.c | 2 +- src/iop/exposure.c | 8 +- src/iop/highlights.c | 2 +- src/iop/rawoverexposed.c | 16 +-- src/libs/live_view.c | 6 +- src/libs/print_settings.c | 5 +- src/lua/image.c | 6 +- src/views/darkroom.c | 4 +- src/views/map.c | 8 +- src/views/slideshow.c | 7 +- src/views/view.c | 11 +- 27 files changed, 233 insertions(+), 244 deletions(-) diff --git a/src/common/cache.c b/src/common/cache.c index b2ce39186fe6..e9484e490a3b 100644 --- a/src/common/cache.c +++ b/src/common/cache.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2011-2024 darktable developers. + Copyright (C) 2011-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -78,10 +78,9 @@ int32_t dt_cache_contains(dt_cache_t *cache, return result; } -int dt_cache_for_all - (dt_cache_t *cache, - int (*process)(const uint32_t key, const void *data, void *user_data), - void *user_data) +int dt_cache_for_all(dt_cache_t *cache, + int (*process)(const uint32_t key, const void *data, void *user_data), + void *user_data) { dt_pthread_mutex_lock(&cache->lock); GHashTableIter iter; @@ -173,11 +172,9 @@ dt_cache_entry_t *dt_cache_get_with_caller(dt_cache_t *cache, if(res) { // yay, found. read lock and pass on. dt_cache_entry_t *entry = (dt_cache_entry_t *)value; - int result; - if(mode == 'w') - result = dt_pthread_rwlock_trywrlock_with_caller(&entry->lock, file, line); - else - result = dt_pthread_rwlock_tryrdlock_with_caller(&entry->lock, file, line); + const int result = (mode == 'w') + ? dt_pthread_rwlock_trywrlock_with_caller(&entry->lock, file, line) + : dt_pthread_rwlock_tryrdlock_with_caller(&entry->lock, file, line); if(result) { // need to give up mutex so other threads have a chance to get in between and // free the lock we're trying to acquire: @@ -224,9 +221,8 @@ dt_cache_entry_t *dt_cache_get_with_caller(dt_cache_t *cache, } // here dies your 32-bit system: - dt_cache_entry_t *entry = (dt_cache_entry_t *)g_slice_alloc(sizeof(dt_cache_entry_t)); - const int ret = dt_pthread_rwlock_init(&entry->lock, 0); - if(ret) dt_print(DT_DEBUG_ALWAYS, "rwlock init: %d", ret); + dt_cache_entry_t *entry = g_slice_alloc(sizeof(dt_cache_entry_t)); + dt_pthread_rwlock_init(&entry->lock, 0); entry->data = 0; entry->data_size = cache->entry_size; @@ -248,8 +244,7 @@ dt_cache_entry_t *dt_cache_get_with_caller(dt_cache_t *cache, ASAN_POISON_MEMORY_REGION(entry->data, entry->data_size); // if allocate callback is given, always return a write lock - const int write = ((mode == 'w') || cache->allocate); - + const gboolean write = ((mode == 'w') || cache->allocate); // write lock in case the caller requests it: if(write) dt_pthread_rwlock_wrlock_with_caller(&entry->lock, file, line); @@ -290,8 +285,7 @@ int dt_cache_remove(dt_cache_t *cache, return 1; } // need write lock to be able to delete: - const int result = dt_pthread_rwlock_trywrlock(&entry->lock); - if(result) + if(dt_pthread_rwlock_trywrlock(&entry->lock)) { dt_pthread_mutex_unlock(&cache->lock); g_usleep(5); @@ -308,7 +302,7 @@ int dt_cache_remove(dt_cache_t *cache, goto restart; } - gboolean removed = g_hash_table_remove(cache->hashtable, GINT_TO_POINTER(key)); + const gboolean removed = g_hash_table_remove(cache->hashtable, GINT_TO_POINTER(key)); (void)removed; // make non-assert compile happy assert(removed); cache->lru = g_list_delete_link(cache->lru, entry->link); diff --git a/src/common/darktable.c b/src/common/darktable.c index 9730c4cbe882..0e93146cc000 100644 --- a/src/common/darktable.c +++ b/src/common/darktable.c @@ -453,10 +453,9 @@ dt_imgid_t dt_load_from_string(const gchar *input, dt_film_open(filmid); // make sure buffers are loaded (load full for testing) dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, - DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); - const gboolean loaded = (buf.buf != NULL); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_get(&buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + const gboolean loaded = buf.buf != NULL; + dt_mipmap_cache_release(&buf); if(!loaded) { imgid = NO_IMGID; @@ -1747,8 +1746,7 @@ int dt_init(int argc, char *argv[], const gboolean init_gui, const gboolean load // image dimensions stored in here: dt_image_cache_init(); - darktable.mipmap_cache = (dt_mipmap_cache_t *)calloc(1, sizeof(dt_mipmap_cache_t)); - dt_mipmap_cache_init(darktable.mipmap_cache); + dt_mipmap_cache_init(); // set up the list of exiv2 metadata dt_exif_set_exiv2_taglist(); @@ -2093,9 +2091,7 @@ void dt_cleanup() dt_image_cache_cleanup(); - dt_mipmap_cache_cleanup(darktable.mipmap_cache); - free(darktable.mipmap_cache); - darktable.mipmap_cache = NULL; + dt_mipmap_cache_cleanup(); dt_colorspaces_cleanup(darktable.color_profiles); dt_conf_cleanup(darktable.conf); diff --git a/src/common/film.c b/src/common/film.c index 7884b6f3e631..597a15f997ec 100644 --- a/src/common/film.c +++ b/src/common/film.c @@ -487,7 +487,7 @@ void dt_film_remove(const dt_filmid_t id) { const dt_imgid_t imgid = sqlite3_column_int(stmt, 0); dt_image_local_copy_reset(imgid); - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); dt_image_cache_remove(imgid); } sqlite3_finalize(stmt); diff --git a/src/common/history.c b/src/common/history.c index 23872da6f6bf..a62ab3a3ac22 100644 --- a/src/common/history.c +++ b/src/common/history.c @@ -129,7 +129,7 @@ void dt_history_delete_on_image_ext(const dt_imgid_t imgid, } /* make sure mipmaps are recomputed */ - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); dt_image_update_final_size(imgid); /* remove darktable|style|* tags */ @@ -204,7 +204,7 @@ gboolean dt_history_load_and_apply(const dt_imgid_t imgid, // ugly but if not history_only => called from crawler - do not write the xmp history_only ? DT_IMAGE_CACHE_SAFE : DT_IMAGE_CACHE_RELAXED, "dt_history_load_and_apply"); - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); dt_image_update_final_size(imgid); } dt_unlock_image(imgid); @@ -981,7 +981,7 @@ gboolean dt_history_copy_and_paste_on_image(const dt_imgid_t imgid, dt_dev_modulegroups_set(darktable.develop, dt_dev_modulegroups_get(darktable.develop)); } - dt_mipmap_cache_remove(darktable.mipmap_cache, dest_imgid); + dt_mipmap_cache_remove(dest_imgid); dt_image_update_final_size(imgid); /* update the aspect ratio. recompute only if really needed for diff --git a/src/common/image.c b/src/common/image.c index cdeb42259aff..3cb94848044d 100644 --- a/src/common/image.c +++ b/src/common/image.c @@ -982,7 +982,7 @@ void dt_image_set_flip(const dt_imgid_t imgid, dt_history_hash_write_from_history(imgid, DT_HISTORY_HASH_CURRENT); - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); dt_image_update_final_size(imgid); dt_image_synch_xmp(imgid); } @@ -1171,20 +1171,13 @@ float dt_image_set_aspect_ratio(const dt_imgid_t imgid, const gboolean raise) dt_mipmap_buffer_t buf; float aspect_ratio = 0.0; - // mipmap cache must be initialized, otherwise we'll update next call - if(darktable.mipmap_cache) + dt_mipmap_cache_get(&buf, imgid, DT_MIPMAP_0, DT_MIPMAP_BLOCKING, 'r'); + if(buf.buf && buf.height && buf.width) { - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_0, - DT_MIPMAP_BLOCKING, 'r'); - - if(buf.buf && buf.height && buf.width) - { - aspect_ratio = (float)buf.width / (float)buf.height; - dt_image_set_aspect_ratio_to(imgid, aspect_ratio, raise); - } - - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + aspect_ratio = (float)buf.width / (float)buf.height; + dt_image_set_aspect_ratio_to(imgid, aspect_ratio, raise); } + dt_mipmap_cache_release(&buf); return aspect_ratio; } @@ -1508,7 +1501,7 @@ void dt_image_remove(const dt_imgid_t imgid) sqlite3_finalize(stmt); // also clear all thumbnails in mipmap_cache. - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_IMAGE_REMOVED, imgid, 0); } @@ -1971,7 +1964,7 @@ static dt_imgid_t _image_import_internal(const dt_filmid_t film_id, dt_tag_attach(tagid, id, FALSE, FALSE); // make sure that there are no stale thumbnails left - dt_mipmap_cache_remove(darktable.mipmap_cache, id); + dt_mipmap_cache_remove(id); // Always keep write timestamp in database and possibly write xmp dt_image_synch_all_xmp(normalized_filename); @@ -2509,7 +2502,7 @@ dt_imgid_t dt_image_copy_rename(const dt_imgid_t imgid, if(dt_is_valid_imgid(newid)) { // also copy over on-disk thumbnails, if any - dt_mipmap_cache_copy_thumbnails(darktable.mipmap_cache, newid, imgid); + dt_mipmap_cache_copy_thumbnails(newid, imgid); // clang-format off DT_DEBUG_SQLITE3_PREPARE_V2(dt_database_get(darktable.db), "INSERT INTO main.color_labels (imgid, color)" diff --git a/src/common/mipmap_cache.c b/src/common/mipmap_cache.c index d5093f61d194..fb119f6bf8c9 100644 --- a/src/common/mipmap_cache.c +++ b/src/common/mipmap_cache.c @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2011-2024 darktable developers. + Copyright (C) 2011-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -173,7 +173,7 @@ static const int dt_mipmap_cache_exif_data_adobergb_length __,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__,__ } -struct dt_mipmap_buffer_dsc +typedef struct dt_mipmap_buffer_dsc_t { uint32_t width; uint32_t height; @@ -190,23 +190,23 @@ struct dt_mipmap_buffer_dsc #endif /* NB: sizeof must be a multiple of 4*sizeof(float) */ -} DT_ALIGNED_ARRAY __attribute__((packed)); +} DT_ALIGNED_ARRAY __attribute__((packed)) dt_mipmap_buffer_dsc_t; #if __has_feature(address_sanitizer) || defined(__SANITIZE_ADDRESS__) -static const size_t dt_mipmap_buffer_dsc_size __attribute__((unused)) -= sizeof(struct dt_mipmap_buffer_dsc) - sizeof(((struct dt_mipmap_buffer_dsc *)0)->redzone); + static const size_t dt_mipmap_buffer_dsc_size __attribute__((unused)) + = sizeof(dt_mipmap_buffer_dsc_t) - sizeof(((dt_mipmap_buffer_dsc_t *)0)->redzone); #else -static const size_t dt_mipmap_buffer_dsc_size __attribute__((unused)) = sizeof(struct dt_mipmap_buffer_dsc); + static const size_t dt_mipmap_buffer_dsc_size __attribute__((unused)) = sizeof(dt_mipmap_buffer_dsc_t); #endif -// last resort mem alloc for dead images. sizeof(dt_mipmap_buffer_dsc) + max static image pixels (14x15) +// last resort mem alloc for dead images. sizeof(dt_mipmap_buffer_dsc_t) + max static image pixels (14x15) // Must be aligned to cache line -static float DT_ALIGNED_ARRAY _mipmap_cache_static_dead_image[sizeof(struct dt_mipmap_buffer_dsc) / sizeof(float) + MIN_IMG_PIXELS * 4]; +static float DT_ALIGNED_ARRAY _mipmap_cache_static_dead_image[sizeof(dt_mipmap_buffer_dsc_t) / sizeof(float) + MIN_IMG_PIXELS * 4]; static inline void _dead_image_8(dt_mipmap_buffer_t *buf) { if(!buf->buf) return; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; dsc->width = 20; dsc->height = 27; dsc->iscale = 1.0f; buf->color_space = dsc->color_space = DT_COLORSPACE_DISPLAY; @@ -222,7 +222,7 @@ static inline void _dead_image_8(dt_mipmap_buffer_t *buf) static inline void _dead_image_f(dt_mipmap_buffer_t *buf) { if(!buf->buf) return; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; dsc->width = 20; dsc->height = 27; dsc->iscale = 1.0f; buf->color_space = dsc->color_space = DT_COLORSPACE_DISPLAY; @@ -236,10 +236,10 @@ static inline void _dead_image_f(dt_mipmap_buffer_t *buf) memcpy(buf->buf, image, sizeof(image)); } -static inline void unsupp_image_8(dt_mipmap_buffer_t *buf) +static inline void _unsupp_image_8(dt_mipmap_buffer_t *buf) { if(!buf->buf) return; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; dsc->width = 17; dsc->height = 25; dsc->iscale = 1.0f; buf->color_space = dsc->color_space = DT_COLORSPACE_DISPLAY; @@ -252,10 +252,10 @@ static inline void unsupp_image_8(dt_mipmap_buffer_t *buf) memcpy(buf->buf, image, sizeof(image)); } -static inline void unsupp_image_f(dt_mipmap_buffer_t *buf) +static inline void _unsupp_image_f(dt_mipmap_buffer_t *buf) { if(!buf->buf) return; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; dsc->width = 17; dsc->height = 25; dsc->iscale = 1.0f; buf->color_space = dsc->color_space = DT_COLORSPACE_DISPLAY; @@ -269,10 +269,10 @@ static inline void unsupp_image_f(dt_mipmap_buffer_t *buf) memcpy(buf->buf, image, sizeof(image)); } -static inline void error_image_8(dt_mipmap_buffer_t *buf) +static inline void _error_image_8(dt_mipmap_buffer_t *buf) { if(!buf->buf) return; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; dsc->width = dsc->height = 29; dsc->iscale = 1.0f; buf->color_space = dsc->color_space = DT_COLORSPACE_DISPLAY; @@ -286,10 +286,10 @@ static inline void error_image_8(dt_mipmap_buffer_t *buf) } //static inline -void error_image_f(dt_mipmap_buffer_t *buf) +static void _error_image_f(dt_mipmap_buffer_t *buf) { if(!buf->buf) return; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; dsc->width = dsc->height = 29; dsc->iscale = 1.0f; buf->color_space = dsc->color_space = DT_COLORSPACE_DISPLAY; @@ -309,10 +309,10 @@ static inline gboolean _is_static_image(void *buffer) } #ifndef NDEBUG -static inline int32_t _buffer_is_broken(dt_mipmap_buffer_t *buf) +static inline gboolean _buffer_is_broken(dt_mipmap_buffer_t *buf) { if(!buf->buf) return 0; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)buf->buf - 1; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)buf->buf - 1; if(buf->width != dsc->width) return 1; if(buf->height != dsc->height) return 2; // somewhat loose bound: @@ -321,14 +321,14 @@ static inline int32_t _buffer_is_broken(dt_mipmap_buffer_t *buf) } #endif -static inline uint32_t get_key(const dt_imgid_t imgid, const dt_mipmap_size_t size) +static inline uint32_t _get_key(const dt_imgid_t imgid, const dt_mipmap_size_t size) { // imgid can't be >= 2^28 (~250 million images) // also ensure a valid key for bad imgid return (((uint32_t)size) << 28) | ((imgid - 1) & 0xfffffff); } -static inline uint32_t get_imgid(const uint32_t key) +static inline uint32_t _get_imgid(const uint32_t key) { return (key & 0xfffffff) + 1; } @@ -399,7 +399,7 @@ void *dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img) assert(buf->size == DT_MIPMAP_FULL); dt_cache_entry_t *entry = buf->cache_entry; - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)entry->data; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)entry->data; const int wd = img->width; const int ht = img->height; @@ -429,7 +429,7 @@ void *dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img) entry->data_size = buffer_size; // set buffer size only if we're making it larger. - dsc = (struct dt_mipmap_buffer_dsc *)entry->data; + dsc = (dt_mipmap_buffer_dsc_t *)entry->data; } dsc->size = buffer_size; @@ -449,7 +449,7 @@ void *dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img) assert(dsc->size <= entry->data_size); ASAN_POISON_MEMORY_REGION(entry->data, entry->data_size); - ASAN_UNPOISON_MEMORY_REGION(dsc + 1, buffer_size - sizeof(struct dt_mipmap_buffer_dsc)); + ASAN_UNPOISON_MEMORY_REGION(dsc + 1, buffer_size - sizeof(dt_mipmap_buffer_dsc_t)); // return pointer to start of payload return dsc + 1; @@ -460,7 +460,7 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry) { dt_mipmap_cache_t *cache = (dt_mipmap_cache_t *)data; // for full image buffers - struct dt_mipmap_buffer_dsc *dsc = entry->data; + dt_mipmap_buffer_dsc_t *dsc = entry->data; const dt_mipmap_size_t mip = _get_size(entry->key); // alloc mere minimum for the header + broken image buffer: @@ -470,9 +470,9 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry) { int imgfw= 0, imgfh= 0; // be sure that we have the right size values - dt_image_get_final_size(get_imgid(entry->key), &imgfw, &imgfh); + dt_image_get_final_size(_get_imgid(entry->key), &imgfw, &imgfh); size_t pixels = MAX((size_t)(imgfw + 4) * (imgfh + 4), MIN_IMG_PIXELS); - entry->data_size = sizeof(struct dt_mipmap_buffer_dsc) + 4 * pixels; + entry->data_size = sizeof(dt_mipmap_buffer_dsc_t) + 4 * pixels; } else if(mip <= DT_MIPMAP_F) { @@ -524,7 +524,7 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry) // try and load from disk, if successful set flag char filename[PATH_MAX] = {0}; snprintf(filename, sizeof(filename), "%s.d/%d/%" PRIu32 ".jpg", cache->cachedir, (int)mip, - get_imgid(entry->key)); + _get_imgid(entry->key)); FILE *f = g_fopen(filename, "rb"); if(f) { @@ -546,12 +546,12 @@ static void _mipmap_cache_allocate_dynamic(void *data, dt_cache_entry_t *entry) { dt_print(DT_DEBUG_ALWAYS, "[mipmap_cache] failed to decompress thumbnail for ID=%d from `%s'!", - get_imgid(entry->key), filename); + _get_imgid(entry->key), filename); goto read_error; } dt_print(DT_DEBUG_CACHE, "[mipmap_cache] grab mip %d for ID=%d from disk cache", mip, - get_imgid(entry->key)); + _get_imgid(entry->key)); dsc->width = jpg.width; dsc->height = jpg.height; dsc->iscale = 1.0f; @@ -605,13 +605,13 @@ static void _mipmap_cache_deallocate_dynamic(void *data, dt_cache_entry_t *entry const dt_mipmap_size_t mip = _get_size(entry->key); if(mip < DT_MIPMAP_F) { - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)entry->data; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)entry->data; // don't write skulls: if(dsc->width > 8 && dsc->height > 8) { if(dsc->flags & DT_MIPMAP_BUFFER_DSC_FLAG_INVALIDATE) { - _mipmap_cache_unlink_ondisk_thumbnail(data, get_imgid(entry->key), mip); + _mipmap_cache_unlink_ondisk_thumbnail(data, _get_imgid(entry->key), mip); } else if(cache->cachedir[0] && ((dt_conf_get_bool("cache_disk_backend") && mip < DT_MIPMAP_8) || (dt_conf_get_bool("cache_disk_backend_full") && mip == DT_MIPMAP_8))) @@ -623,7 +623,7 @@ static void _mipmap_cache_deallocate_dynamic(void *data, dt_cache_entry_t *entry if(!mkd) { snprintf(filename, sizeof(filename), "%s.d/%d/%" PRIu32 ".jpg", cache->cachedir, (int)mip, - get_imgid(entry->key)); + _get_imgid(entry->key)); // Don't write existing files as both performance and quality (lossy jpg) suffer FILE *f = NULL; if(!g_file_test(filename, G_FILE_TEST_EXISTS) && (f = g_fopen(filename, "wb"))) @@ -683,11 +683,14 @@ static uint32_t _nearest_power_of_two(const uint32_t value) return rc; } -void dt_mipmap_cache_init(dt_mipmap_cache_t *cache) +void dt_mipmap_cache_init() { + dt_mipmap_cache_t *cache = calloc(1, sizeof(dt_mipmap_cache_t)); + darktable.mipmap_cache = cache; + _mipmap_cache_get_filename(cache->cachedir, sizeof(cache->cachedir)); // make sure static memory is initialized - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)_mipmap_cache_static_dead_image; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)_mipmap_cache_static_dead_image; _dead_image_f((dt_mipmap_buffer_t *)(dsc + 1)); // adjust numbers to be large enough to hold what mem limit suggests. @@ -721,7 +724,7 @@ void dt_mipmap_cache_init(dt_mipmap_cache_t *cache) } // header + buffer for(int k = DT_MIPMAP_F-1; k >= 0; k--) - cache->buffer_size[k] = sizeof(struct dt_mipmap_buffer_dsc) + cache->buffer_size[k] = sizeof(dt_mipmap_buffer_dsc_t) + (size_t)cache->max_width[k] * cache->max_height[k] * 4; // clear stats: @@ -760,20 +763,27 @@ void dt_mipmap_cache_init(dt_mipmap_cache_t *cache) dt_cache_init(&cache->mip_f.cache, 0, max_mem_bufs); dt_cache_set_allocate_callback(&cache->mip_f.cache, _mipmap_cache_allocate_dynamic, cache); dt_cache_set_cleanup_callback(&cache->mip_f.cache, _mipmap_cache_deallocate_dynamic, cache); - cache->buffer_size[DT_MIPMAP_F] = sizeof(struct dt_mipmap_buffer_dsc) + cache->buffer_size[DT_MIPMAP_F] = sizeof(dt_mipmap_buffer_dsc_t) + 4 * sizeof(float) * cache->max_width[DT_MIPMAP_F] * cache->max_height[DT_MIPMAP_F]; } -void dt_mipmap_cache_cleanup(dt_mipmap_cache_t *cache) +void dt_mipmap_cache_cleanup() { + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + if(!cache) return; + dt_cache_cleanup(&cache->mip_thumbs.cache); dt_cache_cleanup(&cache->mip_full.cache); dt_cache_cleanup(&cache->mip_f.cache); + darktable.mipmap_cache = NULL; + free(cache); } -void dt_mipmap_cache_print(dt_mipmap_cache_t *cache) +void dt_mipmap_cache_print() { + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + if(!cache) return; dt_print(DT_DEBUG_ALWAYS,"[mipmap_cache] thumbs fill %.2f/%.2f MB (%.2f%%)", cache->mip_thumbs.cache.cost / (1024.0 * 1024.0), cache->mip_thumbs.cache.cost_quota / (1024.0 * 1024.0), @@ -838,17 +848,22 @@ static dt_mipmap_cache_one_t *_get_cache(dt_mipmap_cache_t *cache, } } -void dt_mipmap_cache_get_with_caller( - dt_mipmap_cache_t *cache, - dt_mipmap_buffer_t *buf, - const dt_imgid_t imgid, - const dt_mipmap_size_t mip, - const dt_mipmap_get_flags_t flags, - const char mode, - const char *file, - int line) +void dt_mipmap_cache_get_with_caller(dt_mipmap_buffer_t *buf, + const dt_imgid_t imgid, + const dt_mipmap_size_t mip, + const dt_mipmap_get_flags_t flags, + const char mode, + const char *file, + const int line) { - const uint32_t key = get_key(imgid, mip); + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + assert(cache); + if(!cache) + { + buf->buf = NULL; + return; + } + const uint32_t key = _get_key(imgid, mip); // buf may be null when called with DT_MIPMAP_PREFETCH for example if(buf) @@ -862,7 +877,7 @@ void dt_mipmap_cache_get_with_caller( if(entry) { ASAN_UNPOISON_MEMORY_REGION(entry->data, dt_mipmap_buffer_dsc_size); - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)entry->data; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)entry->data; buf->width = dsc->width; buf->height = dsc->height; buf->iscale = dsc->iscale; @@ -873,7 +888,7 @@ void dt_mipmap_cache_get_with_caller( // skip to next 8-byte alignment, for sse buffers. buf->buf = (uint8_t *)(dsc + 1); - ASAN_UNPOISON_MEMORY_REGION(buf->buf, dsc->size - sizeof(struct dt_mipmap_buffer_dsc)); + ASAN_UNPOISON_MEMORY_REGION(buf->buf, dsc->size - sizeof(dt_mipmap_buffer_dsc_t)); } else { @@ -889,16 +904,16 @@ void dt_mipmap_cache_get_with_caller( else if(flags == DT_MIPMAP_PREFETCH) { // and opposite: prefetch without locking - if(mip > DT_MIPMAP_FULL || (int)mip < DT_MIPMAP_0) - return; // remove the (int) once we no longer have to support gcc < 4.8 :/ + if(mip > DT_MIPMAP_FULL || mip < DT_MIPMAP_0) + return; dt_control_add_job(DT_JOB_QUEUE_SYSTEM_FG, dt_image_load_job_create(imgid, mip)); } else if(flags == DT_MIPMAP_PREFETCH_DISK) { // only prefetch if the disk cache exists: if(!cache->cachedir[0]) return; - if(mip > DT_MIPMAP_FULL || (int)mip < DT_MIPMAP_0) - return; // remove the (int) once we no longer have to support gcc < 4.8 :/ + if(mip > DT_MIPMAP_FULL || mip < DT_MIPMAP_0) + return; char filename[PATH_MAX] = {0}; snprintf(filename, sizeof(filename), "%s.d/%d/%"PRIu32".jpg", cache->cachedir, (int)mip, key); // don't attempt to load if disk cache doesn't exist @@ -912,13 +927,13 @@ void dt_mipmap_cache_get_with_caller( ASAN_UNPOISON_MEMORY_REGION(entry->data, dt_mipmap_buffer_dsc_size); - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)entry->data; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)entry->data; buf->cache_entry = entry; - int mipmap_generated = 0; + gboolean mipmap_generated = FALSE; if(dsc->flags & DT_MIPMAP_BUFFER_DSC_FLAG_GENERATE) { - mipmap_generated = 1; + mipmap_generated = TRUE; __sync_fetch_and_add(&(_get_cache(cache, mip)->stats_fetches), 1); // dt_print(DT_DEBUG_ALWAYS, "[mipmap cache get] now initializing buffer for img %u mip %d!", imgid, mip); @@ -949,7 +964,7 @@ void dt_mipmap_cache_get_with_caller( buf->loader_status = ret; // might have been reallocated: ASAN_UNPOISON_MEMORY_REGION(entry->data, dt_mipmap_buffer_dsc_size); - dsc = (struct dt_mipmap_buffer_dsc *)buf->cache_entry->data; + dsc = (dt_mipmap_buffer_dsc_t *)buf->cache_entry->data; if(ret == DT_IMAGEIO_OK) { // swap back new image data: @@ -984,13 +999,13 @@ void dt_mipmap_cache_get_with_caller( } else if(mip == DT_MIPMAP_F) { - ASAN_UNPOISON_MEMORY_REGION(dsc + 1, dsc->size - sizeof(struct dt_mipmap_buffer_dsc)); + ASAN_UNPOISON_MEMORY_REGION(dsc + 1, dsc->size - sizeof(dt_mipmap_buffer_dsc_t)); _init_f(buf, (float *)(dsc + 1), &dsc->width, &dsc->height, &dsc->iscale, imgid); } else { // 8-bit thumbs - ASAN_UNPOISON_MEMORY_REGION(dsc + 1, dsc->size - sizeof(struct dt_mipmap_buffer_dsc)); + ASAN_UNPOISON_MEMORY_REGION(dsc + 1, dsc->size - sizeof(dt_mipmap_buffer_dsc_t)); _init_8((uint8_t *)(dsc + 1), &dsc->width, &dsc->height, &dsc->iscale, &buf->color_space, imgid, mip); } dsc->color_space = buf->color_space; @@ -1011,7 +1026,7 @@ void dt_mipmap_cache_get_with_caller( buf->cache_entry = entry = dt_cache_get(&_get_cache(cache, mip)->cache, key, mode); ASAN_UNPOISON_MEMORY_REGION(entry->data, dt_mipmap_buffer_dsc_size); entry->_lock_demoting = FALSE; - dsc = (struct dt_mipmap_buffer_dsc *)buf->cache_entry->data; + dsc = (dt_mipmap_buffer_dsc_t *)buf->cache_entry->data; } #ifdef _DEBUG @@ -1033,7 +1048,7 @@ void dt_mipmap_cache_get_with_caller( buf->imgid = imgid; buf->size = mip; - ASAN_UNPOISON_MEMORY_REGION(dsc + 1, dsc->size - sizeof(struct dt_mipmap_buffer_dsc)); + ASAN_UNPOISON_MEMORY_REGION(dsc + 1, dsc->size - sizeof(dt_mipmap_buffer_dsc_t)); buf->buf = (uint8_t *)(dsc + 1); if(mipmap_generated) @@ -1045,7 +1060,7 @@ void dt_mipmap_cache_get_with_caller( { // get the loading status of the image from the cache, so that we can assign an appropriate static image dt_image_t *img = dt_image_cache_get(imgid, 'r'); - dt_imageio_retval_t ret = img ? img->load_status : DT_IMAGEIO_FILE_NOT_FOUND; + const dt_imageio_retval_t ret = img ? img->load_status : DT_IMAGEIO_FILE_NOT_FOUND; dt_image_cache_read_release(img); dt_print(DT_DEBUG_PIPE, "[mipmap cache get] got a zero-sized ID=%d mip %d!", imgid, mip); if(mip < DT_MIPMAP_F) @@ -1059,12 +1074,12 @@ void dt_mipmap_cache_get_with_caller( case DT_IMAGEIO_UNSUPPORTED_FORMAT: case DT_IMAGEIO_UNSUPPORTED_CAMERA: case DT_IMAGEIO_UNSUPPORTED_FEATURE: - unsupp_image_8(buf); + _unsupp_image_8(buf); break; case DT_IMAGEIO_LOAD_FAILED: case DT_IMAGEIO_FILE_CORRUPTED: case DT_IMAGEIO_IOERROR: - error_image_8(buf); + _error_image_8(buf); break; } } @@ -1079,12 +1094,12 @@ void dt_mipmap_cache_get_with_caller( case DT_IMAGEIO_UNSUPPORTED_FORMAT: case DT_IMAGEIO_UNSUPPORTED_CAMERA: case DT_IMAGEIO_UNSUPPORTED_FEATURE: - unsupp_image_f(buf); + _unsupp_image_f(buf); break; case DT_IMAGEIO_LOAD_FAILED: case DT_IMAGEIO_FILE_CORRUPTED: case DT_IMAGEIO_IOERROR: - error_image_f(buf); + _error_image_f(buf); break; } } @@ -1101,7 +1116,7 @@ void dt_mipmap_cache_get_with_caller( for(int k = mip; k >= min_mip && k >= 0; k--) { // already loaded? - dt_mipmap_cache_get(cache, buf, imgid, k, DT_MIPMAP_TESTLOCK, 'r'); + dt_mipmap_cache_get(buf, imgid, k, DT_MIPMAP_TESTLOCK, 'r'); if(buf->buf && buf->width > 0 && buf->height > 0) { if(mip != k) __sync_fetch_and_add(&(_get_cache(cache, mip)->stats_standin), 1); @@ -1111,7 +1126,7 @@ void dt_mipmap_cache_get_with_caller( if(mip == k) { __sync_fetch_and_add(&(_get_cache(cache, mip)->stats_near_match), 1); - dt_mipmap_cache_get(cache, buf, imgid, mip, DT_MIPMAP_PREFETCH, 'r'); + dt_mipmap_cache_get(buf, imgid, mip, DT_MIPMAP_PREFETCH, 'r'); } } // couldn't find a smaller thumb, try larger ones only now (these will be slightly slower due to cairo rescaling): @@ -1119,7 +1134,7 @@ void dt_mipmap_cache_get_with_caller( for(int k = mip+1; k <= max_mip; k++) { // already loaded? - dt_mipmap_cache_get(cache, buf, imgid, k, DT_MIPMAP_TESTLOCK, 'r'); + dt_mipmap_cache_get(buf, imgid, k, DT_MIPMAP_TESTLOCK, 'r'); if(buf->buf && buf->width > 0 && buf->height > 0) { __sync_fetch_and_add(&(_get_cache(cache, mip)->stats_standin), 1); @@ -1134,7 +1149,7 @@ void dt_mipmap_cache_get_with_caller( char filename[PATH_MAX] = {0}; snprintf(filename, sizeof(filename), "%s.d/%d/%"PRIu32".jpg", cache->cachedir, (int)mip, key); if(g_file_test(filename, G_FILE_TEST_EXISTS)) - dt_mipmap_cache_get(cache, 0, imgid, DT_MIPMAP_0, DT_MIPMAP_PREFETCH_DISK, 0); + dt_mipmap_cache_get(0, imgid, DT_MIPMAP_0, DT_MIPMAP_PREFETCH_DISK, 0); } // nothing found :( buf->buf = NULL; @@ -1155,12 +1170,14 @@ void dt_mipmap_cache_get_with_caller( imgid, mip, mode, (buf ? buf->buf : NULL)); } -void dt_mipmap_cache_release_with_caller(dt_mipmap_cache_t *cache, - dt_mipmap_buffer_t *buf, +void dt_mipmap_cache_release_with_caller(dt_mipmap_buffer_t *buf, const char *file, int line) { - if(buf->size == DT_MIPMAP_NONE) return; + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + assert(cache); + + if(!buf || buf->size == DT_MIPMAP_NONE) return; assert(dt_is_valid_imgid(buf->imgid)); // assert(buf->size >= DT_MIPMAP_0); // breaks gcc-4.6/4.7 build assert(buf->size < DT_MIPMAP_NONE); @@ -1173,11 +1190,12 @@ void dt_mipmap_cache_release_with_caller(dt_mipmap_cache_t *cache, // return index dt_mipmap_size_t having at least width and height requested instead of minimum combined diff // please note that the requested size is in pixels not dots. -dt_mipmap_size_t dt_mipmap_cache_get_matching_size(const dt_mipmap_cache_t *cache, - const int32_t width, +dt_mipmap_size_t dt_mipmap_cache_get_matching_size(const int32_t width, const int32_t height) { + dt_mipmap_cache_t *cache = darktable.mipmap_cache; dt_mipmap_size_t best = DT_MIPMAP_NONE; + assert(cache); for(int k = DT_MIPMAP_0; k < DT_MIPMAP_F; k++) { best = k; @@ -1200,18 +1218,19 @@ dt_mipmap_size_t dt_mipmap_cache_get_min_mip_from_pref(const char *value) return DT_MIPMAP_NONE; } -void dt_mipmap_cache_remove_at_size(dt_mipmap_cache_t *cache, - const dt_imgid_t imgid, +void dt_mipmap_cache_remove_at_size(const dt_imgid_t imgid, const dt_mipmap_size_t mip) { - if(mip > DT_MIPMAP_8 || mip < DT_MIPMAP_0) return; + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + assert(cache); + if(!cache || mip > DT_MIPMAP_8 || mip < DT_MIPMAP_0) return; // get rid of all ldr thumbnails: - const uint32_t key = get_key(imgid, mip); + const uint32_t key = _get_key(imgid, mip); dt_cache_entry_t *entry = dt_cache_testget(&_get_cache(cache, mip)->cache, key, 'w'); if(entry) { ASAN_UNPOISON_MEMORY_REGION(entry->data, dt_mipmap_buffer_dsc_size); - struct dt_mipmap_buffer_dsc *dsc = (struct dt_mipmap_buffer_dsc *)entry->data; + dt_mipmap_buffer_dsc_t *dsc = (dt_mipmap_buffer_dsc_t *)entry->data; dsc->flags |= DT_MIPMAP_BUFFER_DSC_FLAG_INVALIDATE; dt_cache_release(&_get_cache(cache, mip)->cache, entry); @@ -1225,30 +1244,31 @@ void dt_mipmap_cache_remove_at_size(dt_mipmap_cache_t *cache, } } -void dt_mipmap_cache_remove(dt_mipmap_cache_t *cache, - const dt_imgid_t imgid) +void dt_mipmap_cache_remove(const dt_imgid_t imgid) { for(dt_mipmap_size_t k = DT_MIPMAP_0; k < DT_MIPMAP_F; k++) { - dt_mipmap_cache_remove_at_size(cache, imgid, k); + dt_mipmap_cache_remove_at_size(imgid, k); } } -void dt_mipmap_cache_evict_at_size(dt_mipmap_cache_t *cache, - const dt_imgid_t imgid, + +void dt_mipmap_cache_evict_at_size(const dt_imgid_t imgid, const dt_mipmap_size_t mip) { - const uint32_t key = get_key(imgid, mip); + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + assert(cache); + const uint32_t key = _get_key(imgid, mip); // write thumbnail to disc if not existing there dt_cache_remove(&_get_cache(cache, mip)->cache, key); } -void dt_mimap_cache_evict(dt_mipmap_cache_t *cache, - const dt_imgid_t imgid) +void dt_mipmap_cache_evict(const dt_imgid_t imgid) { + dt_mipmap_cache_t *cache = darktable.mipmap_cache; for(dt_mipmap_size_t k = DT_MIPMAP_0; k < DT_MIPMAP_F; k++) { - const uint32_t key = get_key(imgid, k); + const uint32_t key = _get_key(imgid, k); // write thumbnail to disc if not existing there dt_cache_remove(&_get_cache(cache, k)->cache, key); @@ -1276,7 +1296,7 @@ static void _init_f(dt_mipmap_buffer_t *mipmap_buf, } dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); // lock image after we have the buffer, we might need to lock the image struct for // writing during raw loading, to write to width/height. @@ -1365,7 +1385,7 @@ static void _init_f(dt_mipmap_buffer_t *mipmap_buf, dt_iop_clip_and_zoom(out, (const float *)buf.buf, &roi_out, &roi_in); } - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); *width = roi_out.width; *height = roi_out.height; @@ -1516,7 +1536,7 @@ static void _init_8(uint8_t *buf, for(dt_mipmap_size_t k = size + 1; k < DT_MIPMAP_F; k++) { dt_mipmap_buffer_t tmp; - dt_mipmap_cache_get(darktable.mipmap_cache, &tmp, imgid, k, DT_MIPMAP_TESTLOCK, 'r'); + dt_mipmap_cache_get(&tmp, imgid, k, DT_MIPMAP_TESTLOCK, 'r'); if(tmp.buf == NULL) continue; dt_print(DT_DEBUG_CACHE, @@ -1526,7 +1546,7 @@ static void _init_8(uint8_t *buf, // downsample dt_iop_flip_and_zoom_8(tmp.buf, tmp.width, tmp.height, buf, wd, ht, ORIENTATION_NONE, width, height); - dt_mipmap_cache_release(darktable.mipmap_cache, &tmp); + dt_mipmap_cache_release(&tmp); res = FALSE; break; } @@ -1587,10 +1607,12 @@ dt_colorspaces_color_profile_type_t dt_mipmap_cache_get_colorspace() return DT_COLORSPACE_DISPLAY; } -void dt_mipmap_cache_copy_thumbnails(const dt_mipmap_cache_t *cache, - const dt_imgid_t dst_imgid, +void dt_mipmap_cache_copy_thumbnails(const dt_imgid_t dst_imgid, const dt_imgid_t src_imgid) { + dt_mipmap_cache_t *cache = darktable.mipmap_cache; + assert(cache); + if(cache->cachedir[0] && dt_conf_get_bool("cache_disk_backend") && dt_is_valid_imgid(src_imgid) diff --git a/src/common/mipmap_cache.h b/src/common/mipmap_cache.h index 551b2d500eb9..1c3aef8e3c63 100644 --- a/src/common/mipmap_cache.h +++ b/src/common/mipmap_cache.h @@ -1,6 +1,6 @@ /* This file is part of darktable, - Copyright (C) 2011-2021 darktable developers. + Copyright (C) 2011-2025 darktable developers. darktable is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -109,16 +109,15 @@ typedef struct dt_mipmap_cache_t // function takes care of re-allocating, if necessary. void *dt_mipmap_cache_alloc(dt_mipmap_buffer_t *buf, const dt_image_t *img); -void dt_mipmap_cache_init(dt_mipmap_cache_t *cache); -void dt_mipmap_cache_cleanup(dt_mipmap_cache_t *cache); -void dt_mipmap_cache_print(dt_mipmap_cache_t *cache); +void dt_mipmap_cache_init(void); +void dt_mipmap_cache_cleanup(void); +void dt_mipmap_cache_print(void); // get a buffer and lock according to mode ('r' or 'w'). // see dt_mipmap_get_flags_t for explanation of the exact // behaviour. pass 0 as flags for the default (best effort) -#define dt_mipmap_cache_get(A,B,C,D,E,F) dt_mipmap_cache_get_with_caller(A,B,C,D,E,F,__FILE__,__LINE__) +#define dt_mipmap_cache_get(B,C,D,E,F) dt_mipmap_cache_get_with_caller(B,C,D,E,F,__FILE__,__LINE__) void dt_mipmap_cache_get_with_caller( - dt_mipmap_cache_t *cache, dt_mipmap_buffer_t *buf, const dt_imgid_t imgid, const dt_mipmap_size_t mip, @@ -128,17 +127,16 @@ void dt_mipmap_cache_get_with_caller( int line); // drop a lock -#define dt_mipmap_cache_release(A, B) dt_mipmap_cache_release_with_caller(A, B, __FILE__, __LINE__) -void dt_mipmap_cache_release_with_caller(dt_mipmap_cache_t *cache, dt_mipmap_buffer_t *buf, const char *file, - int line); +#define dt_mipmap_cache_release(A ) dt_mipmap_cache_release_with_caller(A, __FILE__, __LINE__) +void dt_mipmap_cache_release_with_caller(dt_mipmap_buffer_t *buf, const char *file, int line); // remove thumbnails, so they will be regenerated: -void dt_mipmap_cache_remove(dt_mipmap_cache_t *cache, const dt_imgid_t imgid); -void dt_mipmap_cache_remove_at_size(dt_mipmap_cache_t *cache, const dt_imgid_t imgid, const dt_mipmap_size_t mip); +void dt_mipmap_cache_remove(const dt_imgid_t imgid); +void dt_mipmap_cache_remove_at_size(const dt_imgid_t imgid, const dt_mipmap_size_t mip); // evict thumbnails from cache. They will be written to disc if not existing -void dt_mimap_cache_evict(dt_mipmap_cache_t *cache, const dt_imgid_t imgid); -void dt_mipmap_cache_evict_at_size(dt_mipmap_cache_t *cache, const dt_imgid_t imgid, const dt_mipmap_size_t mip); +void dt_mipmap_cache_evict(const dt_imgid_t imgid); +void dt_mipmap_cache_evict_at_size(const dt_imgid_t imgid, const dt_mipmap_size_t mip); // return the closest mipmap size // for the given window you wish to draw. @@ -146,17 +144,14 @@ void dt_mipmap_cache_evict_at_size(dt_mipmap_cache_t *cache, const dt_imgid_t im // depending on the user parameter for the maximum thumbnail dimensions. // actual resolution depends on the image and is only known after // the thumbnail is loaded. -dt_mipmap_size_t dt_mipmap_cache_get_matching_size( - const dt_mipmap_cache_t *cache, - const int32_t width, - const int32_t height); +dt_mipmap_size_t dt_mipmap_cache_get_matching_size(const int32_t width, const int32_t height); // returns the colorspace to use for created thumbnails, takes config into account -dt_colorspaces_color_profile_type_t dt_mipmap_cache_get_colorspace(); +dt_colorspaces_color_profile_type_t dt_mipmap_cache_get_colorspace(void); // copy over thumbnails. used by file operation that copies raw files, to speed up thumbnail generation. // only copies over the jpg backend on disk, doesn't directly affect the in-memory cache. -void dt_mipmap_cache_copy_thumbnails(const dt_mipmap_cache_t *cache, const dt_imgid_t dst_imgid, const dt_imgid_t src_imgid); +void dt_mipmap_cache_copy_thumbnails(const dt_imgid_t dst_imgid, const dt_imgid_t src_imgid); // return the mipmap corresponding to text value saved in prefs dt_mipmap_size_t dt_mipmap_cache_get_min_mip_from_pref(const char *value); diff --git a/src/common/styles.c b/src/common/styles.c index 0147258e3182..090b8afa9125 100644 --- a/src/common/styles.c +++ b/src/common/styles.c @@ -978,7 +978,7 @@ void _styles_apply_to_image_ext(const char *name, } /* remove old obsolete thumbnails */ - dt_mipmap_cache_remove(darktable.mipmap_cache, newimgid); + dt_mipmap_cache_remove(newimgid); dt_image_update_final_size(newimgid); /* update the aspect ratio. recompute only if really needed for performance reasons */ diff --git a/src/control/crawler.c b/src/control/crawler.c index 85ebe9143ea5..659cd5206dc8 100644 --- a/src/control/crawler.c +++ b/src/control/crawler.c @@ -910,8 +910,8 @@ static void _update_img_thumbs(const dt_imgid_t imgid, for(dt_mipmap_size_t k = max_mip; k >= DT_MIPMAP_1; k--) { dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_get(&buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_release(&buf); } // we have written all thumbs now so it's safe to write timestamp, hash and mipsize @@ -927,7 +927,7 @@ static void _update_img_thumbs(const dt_imgid_t imgid, sqlite3_step(stmt); sqlite3_finalize(stmt); - dt_mimap_cache_evict(darktable.mipmap_cache, imgid); + dt_mipmap_cache_evict(imgid); dt_history_hash_set_mipmap(imgid); } diff --git a/src/control/jobs/image_jobs.c b/src/control/jobs/image_jobs.c index bc0000a2d509..fda3d103ea37 100644 --- a/src/control/jobs/image_jobs.c +++ b/src/control/jobs/image_jobs.c @@ -26,13 +26,13 @@ typedef struct dt_image_load_t dt_mipmap_size_t mip; } dt_image_load_t; -static int32_t dt_image_load_job_run(dt_job_t *job) +static int32_t _image_load_job_run(dt_job_t *job) { dt_image_load_t *params = dt_control_job_get_params(job); // hook back into mipmap_cache: dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, params->imgid, params->mip, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, params->imgid, params->mip, DT_MIPMAP_BLOCKING, 'r'); if(buf.buf && buf.height && buf.width) { @@ -42,13 +42,13 @@ static int32_t dt_image_load_job_run(dt_job_t *job) // drop read lock, as this is only speculative async loading. // moved this after the if, because the if never worked because the cache was released. - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); return 0; } dt_job_t *dt_image_load_job_create(dt_imgid_t id, dt_mipmap_size_t mip) { - dt_job_t *job = dt_control_job_create(&dt_image_load_job_run, "load image %d mip %d", id, mip); + dt_job_t *job = dt_control_job_create(&_image_load_job_run, "load image %d mip %d", id, mip); if(!job) return NULL; dt_image_load_t *params = calloc(1, sizeof(dt_image_load_t)); if(!params) @@ -68,7 +68,7 @@ typedef struct dt_image_import_t gchar *filename; } dt_image_import_t; -static int32_t dt_image_import_job_run(dt_job_t *job) +static int32_t _image_import_job_run(dt_job_t *job) { char message[512] = { 0 }; dt_image_import_t *params = dt_control_job_get_params(job); @@ -87,7 +87,7 @@ static int32_t dt_image_import_job_run(dt_job_t *job) return 0; } -static void dt_image_import_job_cleanup(void *p) +static void _image_import_job_cleanup(void *p) { dt_image_import_t *params = p; @@ -99,7 +99,7 @@ static void dt_image_import_job_cleanup(void *p) dt_job_t *dt_image_import_job_create(dt_filmid_t filmid, const char *filename) { dt_image_import_t *params; - dt_job_t *job = dt_control_job_create(&dt_image_import_job_run, "import image"); + dt_job_t *job = dt_control_job_create(&_image_import_job_run, "import image"); if(!job) return NULL; params = calloc(1, sizeof(dt_image_import_t)); if(!params) @@ -108,7 +108,7 @@ dt_job_t *dt_image_import_job_create(dt_filmid_t filmid, const char *filename) return NULL; } dt_control_job_add_progress(job, _("import image"), FALSE); - dt_control_job_set_params(job, params, dt_image_import_job_cleanup); + dt_control_job_set_params(job, params, _image_import_job_cleanup); params->filename = g_strdup(filename); params->film_id = filmid; return job; diff --git a/src/develop/develop.c b/src/develop/develop.c index cdc6726c9572..776dc6a7a518 100644 --- a/src/develop/develop.c +++ b/src/develop/develop.c @@ -316,8 +316,7 @@ void dt_dev_process_image_job(dt_develop_t *dev, dt_get_perf_times(&start); dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, - &buf, dev->image_storage.id, + dt_mipmap_cache_get(&buf, dev->image_storage.id, port ? DT_MIPMAP_FULL : DT_MIPMAP_F, port ? DT_MIPMAP_BLOCKING : DT_MIPMAP_BEST_EFFORT, 'r'); @@ -384,7 +383,7 @@ void dt_dev_process_image_job(dt_develop_t *dev, restart: if(dev->gui_leaving) { - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); dt_control_log_busy_leave(); dt_control_toast_busy_leave(); pipe->status = DT_DEV_PIXELPIPE_INVALID; @@ -442,7 +441,7 @@ void dt_dev_process_image_job(dt_develop_t *dev, // interrupted because image changed? if(dev->image_force_reload || pipe->loading || pipe->input_changed) { - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); dt_control_log_busy_leave(); dt_control_toast_busy_leave(); pipe->status = DT_DEV_PIXELPIPE_INVALID; @@ -467,7 +466,7 @@ void dt_dev_process_image_job(dt_develop_t *dev, pipe->status = DT_DEV_PIXELPIPE_VALID; pipe->loading = FALSE; dev->image_invalid_cnt = 0; - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); // if a widget needs to be redraw there's the DT_SIGNAL_*_PIPE_FINISHED signals dt_control_log_busy_leave(); dt_control_toast_busy_leave(); @@ -514,9 +513,8 @@ static inline void _dt_dev_load_raw(dt_develop_t *dev, dt_mipmap_buffer_t buf; dt_times_t start; dt_get_perf_times(&start); - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, DT_MIPMAP_FULL, - DT_MIPMAP_BLOCKING, 'r'); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_get(&buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_release(&buf); dt_show_times(&start, "[dt_dev_load_raw] loading the image."); const dt_image_t *image = dt_image_cache_get(imgid, 'r'); diff --git a/src/dtgtk/culling.c b/src/dtgtk/culling.c index 0316da15bf17..983a50d1317c 100644 --- a/src/dtgtk/culling.c +++ b/src/dtgtk/culling.c @@ -1131,7 +1131,7 @@ static void _thumbs_prefetch(dt_culling_t *table) maxh = MAX(maxh, th->height); } dt_mipmap_size_t mip = - dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, maxw, maxh); + dt_mipmap_cache_get_matching_size(maxw, maxh); // prefetch next image gchar *query; @@ -1167,7 +1167,7 @@ static void _thumbs_prefetch(dt_culling_t *table) { const dt_imgid_t id = sqlite3_column_int(stmt, 0); if(dt_is_valid_imgid(id)) - dt_mipmap_cache_get(darktable.mipmap_cache, NULL, id, mip, DT_MIPMAP_PREFETCH, 'r'); + dt_mipmap_cache_get(NULL, id, mip, DT_MIPMAP_PREFETCH, 'r'); } sqlite3_finalize(stmt); g_free(query); @@ -1204,7 +1204,7 @@ static void _thumbs_prefetch(dt_culling_t *table) { const dt_imgid_t id = sqlite3_column_int(stmt, 0); if(dt_is_valid_imgid(id)) - dt_mipmap_cache_get(darktable.mipmap_cache, NULL, id, mip, DT_MIPMAP_PREFETCH, 'r'); + dt_mipmap_cache_get(NULL, id, mip, DT_MIPMAP_PREFETCH, 'r'); } sqlite3_finalize(stmt); } @@ -1869,7 +1869,7 @@ void dt_culling_full_redraw(dt_culling_t *table, const gboolean force) dt_print(DT_DEBUG_LIGHTTABLE | DT_DEBUG_PERF, "[dt_culling_full_redraw] done in %0.04f sec", dt_get_wtime() - start); - if(darktable.unmuted & DT_DEBUG_CACHE) dt_mipmap_cache_print(darktable.mipmap_cache); + if(darktable.unmuted & DT_DEBUG_CACHE) dt_mipmap_cache_print(); } gboolean dt_culling_key_move(dt_culling_t *table, dt_culling_move_t move) diff --git a/src/dtgtk/thumbnail.c b/src/dtgtk/thumbnail.c index 14745019e22d..64f8cbadcb71 100644 --- a/src/dtgtk/thumbnail.c +++ b/src/dtgtk/thumbnail.c @@ -458,13 +458,12 @@ static void _get_dimensions_for_img_to_fit(const dt_thumbnail_t *thumb, for(int k = DT_MIPMAP_7; k >= DT_MIPMAP_0; k--) { dt_mipmap_buffer_t tmp; - dt_mipmap_cache_get(darktable.mipmap_cache, &tmp, thumb->imgid, k, - DT_MIPMAP_TESTLOCK, 'r'); + dt_mipmap_cache_get(&tmp, thumb->imgid, k, DT_MIPMAP_TESTLOCK, 'r'); if(tmp.buf) { const int mipw = tmp.width; const int miph = tmp.height; - dt_mipmap_cache_release(darktable.mipmap_cache, &tmp); + dt_mipmap_cache_release(&tmp); if(mipw > 0 && miph > 0) { ar = (float)mipw / miph; diff --git a/src/dtgtk/thumbtable.c b/src/dtgtk/thumbtable.c index 39faec8d9ec7..0f1e5c97c4e9 100644 --- a/src/dtgtk/thumbtable.c +++ b/src/dtgtk/thumbtable.c @@ -1725,7 +1725,7 @@ static void _thumbs_ask_for_discard(dt_thumbtable_t *table) const dt_imgid_t imgid = sqlite3_column_int(stmt, 0); for(int i = max_level - 1; i >= min_level; i--) { - dt_mipmap_cache_remove_at_size(darktable.mipmap_cache, imgid, i); + dt_mipmap_cache_remove_at_size(imgid, i); } } sqlite3_finalize(stmt); @@ -2299,8 +2299,8 @@ static void _event_dnd_begin(GtkWidget *widget, const int id = GPOINTER_TO_INT(table->drag_list->data); dt_mipmap_buffer_t buf; dt_mipmap_size_t mip = - dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, ts, ts); - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, id, mip, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get_matching_size(ts, ts); + dt_mipmap_cache_get(&buf, id, mip, DT_MIPMAP_BLOCKING, 'r'); if(buf.buf) { @@ -2326,7 +2326,7 @@ static void _event_dnd_begin(GtkWidget *widget, g_object_unref(scaled); } - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); } } // if we can reorder, let's update the thumbtable class accordingly @@ -2733,7 +2733,7 @@ void dt_thumbtable_full_redraw(dt_thumbtable_t *table, sqlite3_finalize(stmt); if(darktable.unmuted & DT_DEBUG_CACHE) - dt_mipmap_cache_print(darktable.mipmap_cache); + dt_mipmap_cache_print(); } } diff --git a/src/generate-cache/main.c b/src/generate-cache/main.c index b98a1fa01f03..71c2829ed4a0 100644 --- a/src/generate-cache/main.c +++ b/src/generate-cache/main.c @@ -110,12 +110,12 @@ static int generate_thumbnail_cache(const dt_mipmap_size_t min_mip, const dt_mip // else, generate thumbnail and store in mipmap cache. dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_get(&buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_release(&buf); } // and immediately write thumbs to disc and remove from mipmap cache. - dt_mimap_cache_evict(darktable.mipmap_cache, imgid); + dt_mipmap_cache_evict(imgid); // thumbnail in sync with image dt_history_hash_set_mipmap(imgid); } diff --git a/src/imageio/imageio.c b/src/imageio/imageio.c index 79ab8bb73ef3..897c4ed39251 100644 --- a/src/imageio/imageio.c +++ b/src/imageio/imageio.c @@ -1056,8 +1056,7 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid, dt_set_backthumb_time(600.0); // make sure we don't interfere dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, - DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, imgid, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); const dt_image_t *img = &dev.image_storage; @@ -1486,7 +1485,7 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid, dt_dev_pixelpipe_cleanup(&pipe); dt_dev_cleanup(&dev); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); if(!thumbnail_export && strcmp(format->mime(format_params), "memory") && !(format->flags(format_params) & FORMAT_FLAGS_NO_TMPFILE)) @@ -1525,7 +1524,7 @@ gboolean dt_imageio_export_with_flags(const dt_imgid_t imgid, dt_dev_pixelpipe_cleanup(&pipe); error_early: dt_dev_cleanup(&dev); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); if(!thumbnail_export) dt_set_backthumb_time(5.0); diff --git a/src/iop/demosaic.c b/src/iop/demosaic.c index bbc810a0a6b5..8ac0a6c62014 100644 --- a/src/iop/demosaic.c +++ b/src/iop/demosaic.c @@ -209,7 +209,7 @@ typedef struct dt_iop_demosaic_data_t static gboolean _get_thumb_quality(const int width, const int height) { // we check if we need ultra-high quality thumbnail for this size - const dt_mipmap_size_t level = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, width, height); + const dt_mipmap_size_t level = dt_mipmap_cache_get_matching_size(width, height); const char *min = dt_conf_get_string_const("plugins/lighttable/thumbnail_hq_min_level"); const dt_mipmap_size_t min_s = dt_mipmap_cache_get_min_mip_from_pref(min); diff --git a/src/iop/exposure.c b/src/iop/exposure.c index 94f1548b07b8..44d14dc02c9a 100644 --- a/src/iop/exposure.c +++ b/src/iop/exposure.c @@ -350,13 +350,11 @@ static void _deflicker_prepare_histogram(dt_iop_module_t *self, if(!img || image.buf_dsc.channels != 1 || image.buf_dsc.datatype != TYPE_UINT16) return; dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, - self->dev->image_storage.id, DT_MIPMAP_FULL, - DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, self->dev->image_storage.id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); if(!buf.buf) { dt_control_log(_("failed to get raw buffer from image `%s'"), image.filename); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); return; } @@ -377,7 +375,7 @@ static void _deflicker_prepare_histogram(dt_iop_module_t *self, dt_histogram_helper(&histogram_params, histogram_stats, IOP_CS_RAW, IOP_CS_NONE, buf.buf, histogram, NULL, FALSE, NULL); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); } /* input: 0 - 65535 (valid range: from black level to white level) */ diff --git a/src/iop/highlights.c b/src/iop/highlights.c index 4aff8bc25408..e987a621e5b7 100644 --- a/src/iop/highlights.c +++ b/src/iop/highlights.c @@ -753,7 +753,7 @@ void process(dt_iop_module_t *self, gboolean high_quality = TRUE; if(piece->pipe->type & DT_DEV_PIXELPIPE_THUMBNAIL) { - const dt_mipmap_size_t level = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, piece->pipe->final_width, piece->pipe->final_height); + const dt_mipmap_size_t level = dt_mipmap_cache_get_matching_size(piece->pipe->final_width, piece->pipe->final_height); const char *min = dt_conf_get_string_const("plugins/lighttable/thumbnail_hq_min_level"); const dt_mipmap_size_t min_s = dt_mipmap_cache_get_min_mip_from_pref(min); high_quality = (level >= min_s); diff --git a/src/iop/rawoverexposed.c b/src/iop/rawoverexposed.c index 22e4bfb680d2..5eae7c0dd368 100644 --- a/src/iop/rawoverexposed.c +++ b/src/iop/rawoverexposed.c @@ -131,11 +131,11 @@ void process(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *c dt_iop_image_copy_by_size(ovoid, ivoid, roi_out->width, roi_out->height, ch); dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, image->id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, image->id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); if(!buf.buf) { dt_control_log(_("failed to get raw buffer from image `%s'"), image->filename); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); return; } @@ -217,7 +217,7 @@ void process(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, const void *c dt_free_align(coordbuf); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); if(piece->pipe->mask_display & DT_DEV_PIXELPIPE_DISPLAY_MASK) dt_iop_alpha_copy(ivoid, ovoid, roi_out->width, roi_out->height); } @@ -242,11 +242,11 @@ int process_cl(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_ const dt_image_t *const image = &(dev->image_storage); dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, image->id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, image->id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); if(!buf.buf) { dt_control_log(_("failed to get raw buffer from image `%s'"), image->filename); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); goto error; } @@ -358,7 +358,7 @@ int process_cl(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, cl_mem dev_ dt_opencl_release_mem_object(dev_coord); dt_free_align(coordbuf); dt_opencl_release_mem_object(dev_raw); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); return err; } #endif @@ -377,7 +377,7 @@ void tiling_callback(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, int raw_width = 0; int raw_height = 0; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, image->id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_get(&buf, image->id, DT_MIPMAP_FULL, DT_MIPMAP_BLOCKING, 'r'); if(buf.buf) { @@ -385,7 +385,7 @@ void tiling_callback(dt_iop_module_t *self, dt_dev_pixelpipe_iop_t *piece, raw_height = buf.height; } - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); tiling->factor = 2.5f; // in + out + coordinates tiling->maxbuf = 1.0f; diff --git a/src/libs/live_view.c b/src/libs/live_view.c index b4682e83cb48..27f1edae856b 100644 --- a/src/libs/live_view.c +++ b/src/libs/live_view.c @@ -464,8 +464,8 @@ void gui_post_expose(dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t const float imgwd = 0.97f; dt_mipmap_buffer_t buf; - dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, imgwd * w, imgwd * h); - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, mip, 0, 'r'); + dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(imgwd * w, imgwd * h); + dt_mipmap_cache_get(&buf, imgid, mip, 0, 'r'); float scale = 1.0; cairo_surface_t *surface = NULL; @@ -543,7 +543,7 @@ void gui_post_expose(dt_lib_module_t *self, cairo_t *cr, int32_t width, int32_t cairo_surface_destroy(surface); } cairo_restore(cr); - if(buf.buf) dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + if(buf.buf) dt_mipmap_cache_release(&buf); if(img) dt_image_cache_read_release(img); // ON CANVAS CONTROLS diff --git a/src/libs/print_settings.c b/src/libs/print_settings.c index dfd01b23895a..2f5c74ff92b3 100644 --- a/src/libs/print_settings.c +++ b/src/libs/print_settings.c @@ -1327,8 +1327,7 @@ _intent_callback(GtkWidget *widget, dt_lib_module_t *self) static void _set_orientation(dt_lib_print_settings_t *ps, dt_imgid_t imgid) { dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, - imgid, DT_MIPMAP_0, DT_MIPMAP_BEST_EFFORT, 'r'); + dt_mipmap_cache_get(&buf, imgid, DT_MIPMAP_0, DT_MIPMAP_BEST_EFFORT, 'r'); // If there's a mipmap available, figure out orientation based upon // its dimensions. Otherwise, don't touch orientation until the @@ -1340,7 +1339,7 @@ static void _set_orientation(dt_lib_print_settings_t *ps, dt_imgid_t imgid) dt_bauhaus_combobox_set(ps->orientation, ps->prt.page.landscape == TRUE ? 1 : 0); } - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); dt_control_queue_redraw_center(); } diff --git a/src/lua/image.c b/src/lua/image.c index 6a72b46ef84d..f18dc86d9f37 100644 --- a/src/lua/image.c +++ b/src/lua/image.c @@ -97,7 +97,7 @@ static int drop_cache(lua_State *L) { dt_lua_image_t imgid = NO_IMGID; luaA_to(L, dt_lua_image_t, &imgid, -1); - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); return 0; } @@ -137,8 +137,8 @@ static int generate_cache(lua_State *L) if(dt_util_test_image_file(filename)) continue; // else, generate thumbnail and store in mipmap cache. dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_get(&buf, imgid, k, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_cache_release(&buf); } // thumbnail in sync with image dt_history_hash_set_mipmap(imgid); diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 82b93fa2a2c0..7d3c6f217152 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -1077,7 +1077,7 @@ static gboolean _dev_load_requested_image(gpointer user_data) // be sure light table will update the thumbnail if(!dt_history_hash_is_mipmap_synced(old_imgid)) { - dt_mipmap_cache_remove(darktable.mipmap_cache, old_imgid); + dt_mipmap_cache_remove(old_imgid); dt_image_update_final_size(old_imgid); dt_image_synch_xmp(old_imgid); dt_history_hash_set_mipmap(old_imgid); @@ -3093,7 +3093,7 @@ void leave(dt_view_t *self) // be sure light table will regenerate the thumbnail: if(!dt_history_hash_is_mipmap_synced(imgid)) { - dt_mipmap_cache_remove(darktable.mipmap_cache, imgid); + dt_mipmap_cache_remove(imgid); dt_image_update_final_size(imgid); dt_image_synch_xmp(imgid); dt_history_hash_set_mipmap(imgid); diff --git a/src/views/map.c b/src/views/map.c index e051ac0b635e..4fa00dee7443 100644 --- a/src/views/map.c +++ b/src/views/map.c @@ -1248,11 +1248,9 @@ static GdkPixbuf *_draw_image(const dt_imgid_t imgid, if(thumbnail == DT_MAP_THUMB_THUMB) { - dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, - _thumb_size, _thumb_size); + dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(_thumb_size, _thumb_size); dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, mip, - blocking ? DT_MIPMAP_BLOCKING : DT_MIPMAP_BEST_EFFORT, 'r'); + dt_mipmap_cache_get(&buf, imgid, mip, blocking ? DT_MIPMAP_BLOCKING : DT_MIPMAP_BEST_EFFORT, 'r'); if(buf.buf && buf.width > 0) { @@ -1271,7 +1269,7 @@ static GdkPixbuf *_draw_image(const dt_imgid_t imgid, source = gdk_pixbuf_new_from_data(buf.buf, GDK_COLORSPACE_RGB, TRUE, 8, buf.width, buf.height, buf.width * 4, NULL, NULL); - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); if(!source) goto map_changed_failure; // now we want a slightly larger pixbuf that we can put the image on thumb = gdk_pixbuf_new(GDK_COLORSPACE_RGB, TRUE, 8, w + 2 * _thumb_border, diff --git a/src/views/slideshow.c b/src/views/slideshow.c index ed25c300669c..1aabd704de6c 100644 --- a/src/views/slideshow.c +++ b/src/views/slideshow.c @@ -585,9 +585,8 @@ void expose(dt_view_t *self, { // get a small preview dt_mipmap_buffer_t buf; - dt_mipmap_size_t mip = - dt_mipmap_cache_get_matching_size(darktable.mipmap_cache, width / 8, height / 8); - dt_mipmap_cache_get(darktable.mipmap_cache, &buf, imgid, mip, DT_MIPMAP_BLOCKING, 'r'); + dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(width / 8, height / 8); + dt_mipmap_cache_get(&buf, imgid, mip, DT_MIPMAP_BLOCKING, 'r'); if(buf.buf) { double scale = MIN((double)width / buf.width, (double)height / buf.height); @@ -602,7 +601,7 @@ void expose(dt_view_t *self, } d->id_preview_displayed = imgid; - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); } cairo_restore(cr); diff --git a/src/views/view.c b/src/views/view.c index 8a6d47d26971..136fa4538190 100644 --- a/src/views/view.c +++ b/src/views/view.c @@ -720,26 +720,25 @@ dt_view_surface_value_t dt_view_image_get_surface(const dt_imgid_t imgid, *surface = NULL; // get mipmap cache image - dt_mipmap_cache_t *cache = darktable.mipmap_cache; const int32_t mipwidth = width * darktable.gui->ppd; const int32_t mipheight = height * darktable.gui->ppd; - dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(cache, mipwidth, mipheight); + dt_mipmap_size_t mip = dt_mipmap_cache_get_matching_size(mipwidth, mipheight); // if needed, we load the mimap buffer dt_mipmap_buffer_t buf; - dt_mipmap_cache_get(cache, &buf, imgid, mip, DT_MIPMAP_BEST_EFFORT, 'r'); + dt_mipmap_cache_get(&buf, imgid, mip, DT_MIPMAP_BEST_EFFORT, 'r'); const int32_t buf_wd = buf.width; const int32_t buf_ht = buf.height; dt_print(DT_DEBUG_LIGHTTABLE, "dt_view_image_get_surface id %i, dots %ix%i -> mip %ix%i, found %ix%i", - imgid, mipwidth, mipheight, cache->max_width[mip], cache->max_height[mip], buf_wd, buf_ht); + imgid, mipwidth, mipheight, darktable.mipmap_cache->max_width[mip], darktable.mipmap_cache->max_height[mip], buf_wd, buf_ht); // no image is available at the moment as we didn't get buffer data if(!buf.buf) { - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); return DT_VIEW_SURFACE_KO; } @@ -879,7 +878,7 @@ dt_view_surface_value_t dt_view_image_get_surface(const dt_imgid_t imgid, else ret = DT_VIEW_SURFACE_OK; - dt_mipmap_cache_release(darktable.mipmap_cache, &buf); + dt_mipmap_cache_release(&buf); if(rgbbuf) free(rgbbuf); // logs