Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
image_cache.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2009-2012, 2014 johannes hanika.
4 Copyright (C) 2010-2011 Henrik Andersson.
5 Copyright (C) 2010-2014, 2016 Tobias Ellinghaus.
6 Copyright (C) 2011 Robert Bieber.
7 Copyright (C) 2011 Rostyslav Pidgornyi.
8 Copyright (C) 2012 Richard Wonka.
9 Copyright (C) 2013 Simon Spannagel.
10 Copyright (C) 2013 Ulrich Pegelow.
11 Copyright (C) 2014-2015 Pedro Côrte-Real.
12 Copyright (C) 2014-2016 Roman Lebedev.
13 Copyright (C) 2018 Edgardo Hoszowski.
14 Copyright (C) 2019 Andreas Schneider.
15 Copyright (C) 2019 August Schwerdfeger.
16 Copyright (C) 2019 Bill Ferguson.
17 Copyright (C) 2019-2020 Hanno Schwalm.
18 Copyright (C) 2019-2022 Pascal Obry.
19 Copyright (C) 2020 Heiko Bauke.
20 Copyright (C) 2020 JP Verrue.
21 Copyright (C) 2020, 2022 Philippe Weyland.
22 Copyright (C) 2021 Aldric Renaudin.
23 Copyright (C) 2021 Vincent THOMAS.
24 Copyright (C) 2022 Martin Bařinka.
25 Copyright (C) 2022 paolodepetrillo.
26 Copyright (C) 2022 Philipp Lutz.
27 Copyright (C) 2025-2026 Aurélien PIERRE.
28
29 darktable is free software: you can redistribute it and/or modify
30 it under the terms of the GNU General Public License as published by
31 the Free Software Foundation, either version 3 of the License, or
32 (at your option) any later version.
33
34 darktable is distributed in the hope that it will be useful,
35 but WITHOUT ANY WARRANTY; without even the implied warranty of
36 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
37 GNU General Public License for more details.
38
39 You should have received a copy of the GNU General Public License
40 along with darktable. If not, see <http://www.gnu.org/licenses/>.
41*/
42
43#include "common/image_cache.h"
44#include "common/colorlabels.h"
45#include "common/darktable.h"
46#include "common/debug.h"
47#include "common/exif.h"
48#include "common/image.h"
49#include "common/imageio.h"
50#include "common/datetime.h"
51#include "control/conf.h"
52#include "control/control.h"
53#include "control/jobs.h"
54#include "control/signal.h"
55#include "develop/develop.h"
56#include "develop/supervisor.h"
57
58#include <sqlite3.h>
59#include <inttypes.h>
60#include <math.h>
61
62static sqlite3_stmt *_image_cache_load_stmt = NULL;
63static sqlite3_stmt *_image_cache_write_history_hash_stmt = NULL;
64static dt_pthread_mutex_t _image_cache_stmt_mutex;
66
67static inline void _image_cache_stmt_mutex_ensure(void)
68{
69 if(g_once_init_enter(&_image_cache_stmt_mutex_inited))
70 {
72 g_once_init_leave(&_image_cache_stmt_mutex_inited, 1);
73 }
74}
75
77{
78 if(IS_NULL_PTR(img) || img->id <= 0) return 0;
79
80 struct
81 {
82 dt_image_orientation_t orientation;
83 float exif_exposure;
84 float exif_exposure_bias;
85 float exif_aperture;
86 float exif_iso;
87 float exif_focal_length;
88 float exif_focus_distance;
89 float exif_crop;
90 char exif_maker[64];
91 char exif_model[64];
92 char exif_lens[128];
93 GTimeSpan exif_datetime_taken;
94 char filename[DT_MAX_FILENAME_LEN];
95 int32_t width, height;
96 int32_t crop_x, crop_y, crop_width, crop_height;
97 int32_t flags, film_id, id, group_id, version;
98 uint64_t history_hash;
99 float d65_color_matrix[9];
100 dt_image_colorspace_t colorspace;
101 dt_image_raw_parameters_t legacy_flip;
102 dt_image_geoloc_t geoloc;
103 uint16_t raw_black_level;
104 uint32_t raw_white_point;
105 int color_labels;
106 } persisted = { 0 };
107
108 /*
109 * Track only the dt_image_t fields that are explicitly written back to the database
110 * from dt_image_cache_write_release(), plus the history hash and color labels that
111 * are flushed through their own SQL paths right below it. Runtime-only fields such
112 * as cached ICC pointers, DNG gain-map lists, loader state or derived path strings
113 * must stay out of this hash, otherwise merely opening an image can look like an
114 * edit and spuriously bump change_timestamp.
115 */
116 persisted.orientation = img->orientation;
117 persisted.exif_exposure = img->exif_exposure;
118 persisted.exif_exposure_bias = img->exif_exposure_bias;
119 persisted.exif_aperture = img->exif_aperture;
120 persisted.exif_iso = img->exif_iso;
121 persisted.exif_focal_length = img->exif_focal_length;
122 persisted.exif_focus_distance = img->exif_focus_distance;
123 persisted.exif_crop = img->exif_crop;
124 memcpy(persisted.exif_maker, img->exif_maker, sizeof(persisted.exif_maker));
125 memcpy(persisted.exif_model, img->exif_model, sizeof(persisted.exif_model));
126 memcpy(persisted.exif_lens, img->exif_lens, sizeof(persisted.exif_lens));
127 persisted.exif_datetime_taken = img->exif_datetime_taken;
128 memcpy(persisted.filename, img->filename, sizeof(persisted.filename));
129 persisted.width = img->width;
130 persisted.height = img->height;
131 persisted.crop_x = img->crop_x;
132 persisted.crop_y = img->crop_y;
133 persisted.crop_width = img->crop_width;
134 persisted.crop_height = img->crop_height;
135 persisted.flags = img->flags;
136 persisted.film_id = img->film_id;
137 persisted.id = img->id;
138 persisted.group_id = img->group_id;
139 persisted.version = img->version;
140 persisted.history_hash = img->history_hash;
141 memcpy(persisted.d65_color_matrix, img->d65_color_matrix, sizeof(persisted.d65_color_matrix));
142 persisted.colorspace = img->colorspace;
143 persisted.legacy_flip = img->legacy_flip;
144 persisted.geoloc = img->geoloc;
145 persisted.raw_black_level = img->raw_black_level;
146 persisted.raw_white_point = img->raw_white_point;
147 persisted.color_labels = img->color_labels;
148
149 return dt_hash(5381, (const char *)&persisted, sizeof(persisted));
150}
151
152static inline void _image_cache_lock_init(dt_image_t *img)
153{
155}
156
158{
159 if(IS_NULL_PTR(img) || img->id <= 0) return;
160
164 {
165 // clang-format off
168 "INSERT INTO main.history_hash (imgid, current_hash, basic_hash, auto_hash, mipmap_hash)"
169 " VALUES (?1, ?2, NULL, NULL, ?3)"
170 " ON CONFLICT (imgid)"
171 " DO UPDATE SET current_hash = ?2, basic_hash = NULL, auto_hash = NULL, mipmap_hash = ?3",
173 // clang-format on
174 }
175 sqlite3_stmt *stmt = _image_cache_write_history_hash_stmt;
176 sqlite3_reset(stmt);
177 sqlite3_clear_bindings(stmt);
178 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img->id);
179 DT_DEBUG_SQLITE3_BIND_INT64(stmt, 2, (sqlite3_int64)img->history_hash);
180 DT_DEBUG_SQLITE3_BIND_INT64(stmt, 3, (sqlite3_int64)img->mipmap_hash);
181 sqlite3_step(stmt);
183}
184
185static sqlite3_stmt *_image_cache_get_stmt(void)
186{
188 {
189 // clang-format off
192 "SELECT i.id, i.group_id, "
193 " (SELECT COUNT(id) FROM main.images WHERE group_id = i.group_id), "
194 " (SELECT COUNT(imgid) FROM main.history WHERE imgid = i.id), "
195 " COALESCE((SELECT current_hash FROM main.history_hash WHERE imgid = i.id), -1), "
196 " COALESCE((SELECT mipmap_hash FROM main.history_hash WHERE imgid = i.id), -1), "
197 " i.film_id, i.version, i.width, i.height, i.orientation, i.flags, "
198 " i.import_timestamp, i.change_timestamp, i.export_timestamp, i.print_timestamp, "
199 " i.exposure, i.exposure_bias, i.aperture, i.iso, i.focal_length, i.focus_distance, "
200 " i.datetime_taken, i.longitude, i.latitude, i.altitude, "
201 " i.filename, f.folder || '" G_DIR_SEPARATOR_S "' || i.filename, "
202 " i.maker, i.model, i.lens, f.folder, "
203 " COALESCE((SELECT SUM(1 << color) FROM main.color_labels WHERE imgid=i.id), 0), "
204 " i.crop, i.raw_parameters, i.color_matrix, i.colorspace, "
205 " i.raw_black, i.raw_maximum, i.aspect_ratio, i.output_width, i.output_height"
206 " FROM main.images AS i"
207 " LEFT JOIN main.film_rolls AS f ON f.id = i.film_id"
208 " WHERE i.id = ?1",
209 -1, &_image_cache_load_stmt, NULL);
210 // clang-format on
211 }
212
213 sqlite3_reset(_image_cache_load_stmt);
214 sqlite3_clear_bindings(_image_cache_load_stmt);
216}
217
218void dt_image_from_stmt(dt_image_t *img, sqlite3_stmt *stmt)
219{
220 if(sqlite3_column_type(stmt, 0) != SQLITE_NULL) img->id = sqlite3_column_int(stmt, 0);
221 if(sqlite3_column_type(stmt, 1) != SQLITE_NULL) img->group_id = sqlite3_column_int(stmt, 1);
222 if(sqlite3_column_type(stmt, 2) != SQLITE_NULL) img->group_members = (uint32_t)sqlite3_column_int(stmt, 2);
223 if(sqlite3_column_type(stmt, 3) != SQLITE_NULL) img->history_items = (uint32_t)sqlite3_column_int(stmt, 3);
224 if(sqlite3_column_type(stmt, 4) != SQLITE_NULL) img->history_hash = sqlite3_column_int64(stmt, 4);
225 if(sqlite3_column_type(stmt, 5) != SQLITE_NULL) img->mipmap_hash = sqlite3_column_int64(stmt, 5);
226 if(sqlite3_column_type(stmt, 6) != SQLITE_NULL) img->film_id = sqlite3_column_int(stmt, 6);
227 if(sqlite3_column_type(stmt, 7) != SQLITE_NULL) img->version = sqlite3_column_int(stmt, 7);
228 if(sqlite3_column_type(stmt, 8) != SQLITE_NULL) img->width = sqlite3_column_int(stmt, 8);
229 if(sqlite3_column_type(stmt, 9) != SQLITE_NULL) img->height = sqlite3_column_int(stmt, 9);
230 if(sqlite3_column_type(stmt, 10) != SQLITE_NULL) img->orientation = sqlite3_column_int(stmt, 10);
231 if(sqlite3_column_type(stmt, 11) != SQLITE_NULL) img->flags = sqlite3_column_int(stmt, 11);
232 if(sqlite3_column_type(stmt, 12) != SQLITE_NULL) img->import_timestamp = sqlite3_column_int64(stmt, 12);
233 if(sqlite3_column_type(stmt, 13) != SQLITE_NULL) img->change_timestamp = sqlite3_column_int64(stmt, 13);
234 if(sqlite3_column_type(stmt, 14) != SQLITE_NULL) img->export_timestamp = sqlite3_column_int64(stmt, 14);
235 if(sqlite3_column_type(stmt, 15) != SQLITE_NULL) img->print_timestamp = sqlite3_column_int64(stmt, 15);
236 if(sqlite3_column_type(stmt, 16) != SQLITE_NULL) img->exif_exposure = sqlite3_column_double(stmt, 16);
237 if(sqlite3_column_type(stmt, 17) != SQLITE_NULL) img->exif_exposure_bias = sqlite3_column_double(stmt, 17);
238 if(sqlite3_column_type(stmt, 18) != SQLITE_NULL) img->exif_aperture = sqlite3_column_double(stmt, 18);
239 if(sqlite3_column_type(stmt, 19) != SQLITE_NULL) img->exif_iso = sqlite3_column_double(stmt, 19);
240 if(sqlite3_column_type(stmt, 20) != SQLITE_NULL) img->exif_focal_length = sqlite3_column_double(stmt, 20);
241 if(sqlite3_column_type(stmt, 21) != SQLITE_NULL) img->exif_focus_distance = sqlite3_column_double(stmt, 21);
242 if(sqlite3_column_type(stmt, 22) != SQLITE_NULL) img->exif_datetime_taken = sqlite3_column_int64(stmt, 22);
243 if(sqlite3_column_type(stmt, 23) != SQLITE_NULL) img->geoloc.longitude = sqlite3_column_double(stmt, 23);
244 if(sqlite3_column_type(stmt, 24) != SQLITE_NULL) img->geoloc.latitude = sqlite3_column_double(stmt, 24);
245 if(sqlite3_column_type(stmt, 25) != SQLITE_NULL) img->geoloc.elevation = sqlite3_column_double(stmt, 25);
246
247 const char *filename = (const char *)sqlite3_column_text(stmt, 26);
248 if(filename) g_strlcpy(img->filename, filename, sizeof(img->filename));
249 const char *fullpath = (const char *)sqlite3_column_text(stmt, 27);
250 if(fullpath) g_strlcpy(img->fullpath, fullpath, sizeof(img->fullpath));
251 const char *maker = (const char *)sqlite3_column_text(stmt, 28);
252 if(maker) g_strlcpy(img->exif_maker, maker, sizeof(img->exif_maker));
253 const char *model = (const char *)sqlite3_column_text(stmt, 29);
254 if(model) g_strlcpy(img->exif_model, model, sizeof(img->exif_model));
255 const char *lens = (const char *)sqlite3_column_text(stmt, 30);
256 if(lens) g_strlcpy(img->exif_lens, lens, sizeof(img->exif_lens));
257 const char *folder = (const char *)sqlite3_column_text(stmt, 31);
258 if(folder) g_strlcpy(img->folder, folder, sizeof(img->folder));
259
260 if(sqlite3_column_type(stmt, 32) != SQLITE_NULL) img->color_labels = sqlite3_column_int(stmt, 32);
261
262 if(sqlite3_column_type(stmt, 33) != SQLITE_NULL) img->exif_crop = sqlite3_column_double(stmt, 33);
263 if(sqlite3_column_type(stmt, 34) != SQLITE_NULL)
264 {
265 uint32_t tmp = sqlite3_column_int(stmt, 34);
266 memcpy(&img->legacy_flip, &tmp, sizeof(dt_image_raw_parameters_t));
267 }
268 const void *color_matrix = sqlite3_column_blob(stmt, 35);
269 if(color_matrix) memcpy(img->d65_color_matrix, color_matrix, sizeof(img->d65_color_matrix));
270 if(sqlite3_column_type(stmt, 36) != SQLITE_NULL) img->colorspace = sqlite3_column_int(stmt, 36);
271 if(sqlite3_column_type(stmt, 37) != SQLITE_NULL) img->raw_black_level = sqlite3_column_int(stmt, 37);
272 if(sqlite3_column_type(stmt, 38) != SQLITE_NULL) img->raw_white_point = sqlite3_column_int(stmt, 38);
273
274 if(img->fullpath[0])
276 sizeof(img->local_copy_path), img->local_copy_legacy_path,
277 sizeof(img->local_copy_legacy_path));
278
279 img->exif_inited = (img->exif_focus_distance >= 0 && img->orientation >= 0);
280
281 if(img->folder[0])
282 g_strlcpy(img->filmroll, dt_image_film_roll_name(img->folder), sizeof(img->filmroll));
283
285
286 // img->dsc are written by imageio drivers : never (re)set them from DB,
287 // they are not saved anyway. Until the codec decodes the file, seed a provisional
288 // descriptor from the (extension-derived) pipeline class so the image can be reasoned
289 // about and the first pipeline stage has a usable contract even before decoding.
291
293 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
294 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
295 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
298 img->is_hdr = dt_image_is_hdr(img);
299
300 // Instrumentation: the LDR/HDR flags are now pure flag predicates (no filename sniffing at read
301 // time). Historically the flag could have been mis-set at import, so cross-check the flags loaded
302 // from the DB against the unambiguous extension hint and log any contradiction. Containers whose
303 // dynamic range only the decoder can settle (TIFF/AVIF/HEIF/DNG ...) return 0 here and are skipped
304 // to avoid false positives. This surfaces stale/garbage flags persisted in the database.
305 {
306 const gchar *ext = g_strrstr(img->filename, ".");
307 const dt_image_flags_t ext_hint = ext ? dt_imageio_get_type_from_extension(ext) : 0;
308 const gboolean db_hdr = (img->flags & DT_IMAGE_HDR) != 0;
309 const gboolean db_ldr = (img->flags & DT_IMAGE_LDR) != 0;
310
311 if(ext_hint == DT_IMAGE_HDR && !db_hdr)
313 "[image_cache] DB flag mismatch: id=%d filename='%s' has an HDR extension but stored "
314 "flags=0x%08x lack DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
315 img->id, img->filename, (unsigned int)img->flags, db_ldr, db_hdr);
316 else if((ext_hint == DT_IMAGE_LDR || ext_hint == DT_IMAGE_RAW) && db_hdr)
318 "[image_cache] DB flag mismatch: id=%d filename='%s' has a %s extension but stored "
319 "flags=0x%08x carry DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
320 img->id, img->filename, (ext_hint == DT_IMAGE_RAW) ? "RAW" : "LDR",
321 (unsigned int)img->flags, db_ldr, db_hdr);
322 }
323
325}
326
327static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid, const dt_sv_op_t sv_op)
328{
331
332 sqlite3_stmt *stmt = _image_cache_get_stmt();
333 sqlite3_reset(stmt);
334 sqlite3_clear_bindings(stmt);
335 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, imgid);
336 if(sqlite3_step(stmt) == SQLITE_ROW)
337 {
338 dt_image_from_stmt(img, stmt);
339
340 /* Deprecated:
341 if(sqlite3_column_type(stmt, 37) == SQLITE_FLOAT)
342 img->aspect_ratio = sqlite3_column_double(stmt, 37);
343 else
344 img->aspect_ratio = 0.0;
345 */
346
347 /* Deprecated:
348 img->final_width = sqlite3_column_int(stmt, 33);
349 img->final_height = sqlite3_column_int(stmt, 34);
350 */
351 }
352 else
353 {
354 img->id = -1;
355 fprintf(stderr, "[image_cache_reload] failed to open image %" PRIu32 " from database: %s\n", imgid,
356 sqlite3_errmsg(dt_database_get(darktable.db)));
357 }
358
360
361 // The image's dt_image_t was just (re)loaded from the database: `create` on
362 // first allocation, `update` on a reload (get_reload / IMAGE_INFO_CHANGED).
363 if(dt_supervisor_active()) dt_supervisor_image(sv_op, (int32_t)imgid, img);
364}
365
367{
368 entry->cost = sizeof(dt_image_t);
369
370 dt_image_t *img = (dt_image_t *)g_malloc(sizeof(dt_image_t));
371 entry->data = img;
372 dt_image_init(img);
373 _image_cache_reload_from_db(img, entry->key, DT_SV_CREATE); // emits the create event
374
375 img->cache_entry = entry; // init backref
376}
377
379{
380 dt_image_t *img = (dt_image_t *)entry->data;
381
382 if(dt_supervisor_active()) dt_supervisor_image(DT_SV_DELETE, (int32_t)entry->key, NULL);
383
384 dt_free(img->profile);
385 g_list_free_full(img->dng_gain_maps, dt_free_gpointer);
386 img->dng_gain_maps = NULL;
387 dt_free(img);
388}
389
391{
392 // the image cache does no serialization.
393 // (unsafe. data should be in db/xmp, not in any other additional cache,
394 // also, it should be relatively fast to get the image_t structs from sql.)
395 // TODO: actually an independent conf var?
396 // too large: dangerous and wasteful?
397 // can we get away with a fixed size?
398 const uint32_t size = 50;
399 const uint32_t max_mem = size * 1024 * 1024;
400 const uint32_t num = (uint32_t)(1.5f * max_mem / sizeof(dt_image_t));
401 dt_cache_init(&cache->cache, sizeof(dt_image_t), max_mem);
404
405 dt_print(DT_DEBUG_CACHE, "[image_cache] has %d entries (%u MiB)\n", num, size);
406}
407
428
430{
431 printf("[image cache] fill %.2f/%.2f MB (%.2f%%)\n", cache->cache.cost / (1024.0 * 1024.0),
432 cache->cache.cost_quota / (1024.0 * 1024.0),
433 (float)cache->cache.cost / (float)cache->cache.cost_quota);
434}
435
436void dt_image_cache_get_usage(dt_image_cache_t *cache, size_t *current, size_t *max)
437{
438 if(current) *current = 0;
439 if(max) *max = 0;
440 if(IS_NULL_PTR(cache)) return;
442 if(current) *current = cache->cache.cost;
443 if(max) *max = cache->cache.cost_quota;
445}
446
448{
449 GArray *out = g_array_new(FALSE, FALSE, sizeof(dt_image_cache_stats_entry_t));
450 if(IS_NULL_PTR(cache)) return out;
451
453 GHashTableIter it;
454 gpointer key, value;
455 g_hash_table_iter_init(&it, cache->cache.hashtable);
456 while(g_hash_table_iter_next(&it, &key, &value))
457 {
458 const dt_cache_entry_t *ce = (const dt_cache_entry_t *)value;
459 if(IS_NULL_PTR(ce)) continue;
461 s.imgid = (int32_t)ce->key;
462 s.size = ce->cost ? ce->cost : ce->data_size;
463 const dt_image_t *img = (const dt_image_t *)ce->data;
464 if(img && img->filename[0]) g_strlcpy(s.filename, img->filename, sizeof(s.filename));
465 g_array_append_val(out, s);
466 }
468 return out;
469}
470
471dt_image_t *dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
472{
473 if(imgid <= 0) return NULL;
474 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, mode);
476 dt_image_t *img = (dt_image_t *)entry->data;
477 img->cache_entry = entry;
478
479 if(dt_image_invalid(img))
480 {
481 dt_cache_release(&cache->cache, entry);
482 return NULL;
483 }
484
486 return img;
487}
488
489dt_image_t *dt_image_cache_testget(dt_image_cache_t *cache, const int32_t imgid, char mode)
490{
491 if(imgid <= 0) return NULL;
492 dt_cache_entry_t *entry = dt_cache_testget(&cache->cache, (uint32_t)imgid, mode);
493 if(IS_NULL_PTR(entry)) return 0;
495 dt_image_t *img = (dt_image_t *)entry->data;
496 img->cache_entry = entry;
498 return img;
499}
500
501// Always reload the cache entry from DB before returning it.
502// This is critical for IMAGE_INFO_CHANGED: other handlers will read from the cache.
503dt_image_t *dt_image_cache_get_reload(dt_image_cache_t *cache, const int32_t imgid, char mode)
504{
505 if(imgid <= 0) return NULL;
506
507 // We must take a write lock to reload in-place, then demote to read if requested.
508 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'w');
510 dt_image_t *img = (dt_image_t *)entry->data;
511 _image_cache_reload_from_db(img, (uint32_t)imgid, DT_SV_UPDATE);
512
513 img->cache_entry = entry;
514
515 if(dt_image_invalid(img))
516 {
517 dt_cache_release(&cache->cache, entry);
518 return NULL;
519 }
520
521 if(mode == 'r')
522 {
523 // demote the lock to read mode (see mipmap cache for rationale)
524 entry->_lock_demoting = 1;
525 dt_cache_release(&cache->cache, entry);
526 entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'r');
527 entry->_lock_demoting = 0;
529 img = (dt_image_t *)entry->data;
530 img->cache_entry = entry;
531 }
532
534 return img;
535}
536
538{
539 return (IS_NULL_PTR(img) || img->id <= 0);
540}
541
543{
544 if(IS_NULL_PTR(cache) || dt_image_invalid(img)) return -1;
545
546 dt_image_t seeded = *img;
547
548 // Avoid ownership issues for pointers that the cache cleanup would free.
549 seeded.profile = NULL;
550 seeded.profile_size = 0;
551 seeded.dng_gain_maps = NULL;
552 seeded.cache_entry = NULL;
553
554 return dt_cache_seed(&cache->cache, (uint32_t)seeded.id, &seeded, sizeof(dt_image_t), sizeof(dt_image_t), FALSE);
555}
556
557// This callback must run before any other DT_SIGNAL_IMAGE_INFO_CHANGED handler.
558// The signal notifies about DB changes, and most listeners read image info from the cache.
559// We therefore force a DB reload here so every subsequent handler sees up-to-date data.
560static void _image_cache_info_changed_reload_callback(gpointer instance, gpointer imgs, gpointer user_data)
561{
562 for(GList *l = g_list_first((GList *)imgs); l; l = g_list_next(l))
563 {
564 const int32_t imgid = GPOINTER_TO_INT(l->data);
565 if(imgid <= 0) continue;
566
568 if(img)
570 }
571}
572
574{
575 // Must be connected early to run before any other handler.
578}
579
580// drops the read lock on an image struct
582{
583 if(IS_NULL_PTR(img) || img->id <= 0) return;
584 const uint64_t self_hash = _image_cache_self_hash(img);
585 if(self_hash != img->self_hash)
586 g_error("[image_cache] read lock modified image %d, you need to use a write lock\n", img->id);
587
588 // just force the dt_image_t struct to make sure it has been locked before.
589 dt_cache_release(&cache->cache, img->cache_entry);
590}
591
592// drops the write privileges on an image struct.
593// this triggers a write-through to sql, and optionally queues xmp sidecar writing.
595{
596 union {
598 uint32_t u;
599 } flip;
600 if(IS_NULL_PTR(img) || img->id <= 0) return;
601
602 const uint64_t self_hash = _image_cache_self_hash(img);
603 const gboolean changed = (self_hash != img->self_hash);
604
605 if(changed)
607
608 // even if nothing changed, we might need to write export/print timestamps
609 // and mipmap hash, so we can't exit just yet.
610
611 if(mode == DT_IMAGE_CACHE_MINIMAL)
612 {
613 if(changed)
614 g_error("[image_cache] minimal write release modified image %d, you need to commit those changes to DB.\n", img->id);
615
616 dt_cache_release(&cache->cache, img->cache_entry);
617 return;
618 }
619
620 // Recompute full/local copy paths (and derived folder/filmroll/datetime) from possibly updated filename.
621 // Avoid SQL here; rely on the cached folder/fullpath, or leave fields empty if they can't be rebuilt.
622 char folder[PATH_MAX] = { 0 };
623 if(img->folder[0])
624 {
625 g_strlcpy(folder, img->folder, sizeof(folder));
626 }
627 else if(img->fullpath[0])
628 {
629 gchar *dir = g_path_get_dirname(img->fullpath);
630 if(dir && dir[0] && strcmp(dir, "."))
631 g_strlcpy(folder, dir, sizeof(folder));
632 dt_free(dir);
633 }
634
635 if(img->filename[0] && folder[0])
636 {
637 g_snprintf(img->fullpath, sizeof(img->fullpath), "%s" G_DIR_SEPARATOR_S "%s", folder, img->filename);
638 g_strlcpy(img->folder, folder, sizeof(img->folder));
639 }
640 else
641 {
642 img->fullpath[0] = '\0';
643 img->folder[0] = '\0';
644 }
645 if(img->folder[0])
646 g_strlcpy(img->filmroll, dt_image_film_roll_name(img->folder), sizeof(img->filmroll));
647 else if(img->film_id < 0)
648 g_strlcpy(img->filmroll, _("orphaned image"), sizeof(img->filmroll));
649 else
650 img->filmroll[0] = '\0';
653 sizeof(img->local_copy_path), img->local_copy_legacy_path,
654 sizeof(img->local_copy_legacy_path));
655
657 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
658 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
659 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
662 img->is_hdr = dt_image_is_hdr(img);
663
664 sqlite3_stmt *stmt;
665 // clang-format off
667 "UPDATE main.images"
668 " SET width = ?1, height = ?2, filename = ?3, maker = ?4, model = ?5,"
669 " lens = ?6, exposure = ?7, aperture = ?8, iso = ?9, focal_length = ?10,"
670 " focus_distance = ?11, film_id = ?12, datetime_taken = ?13, flags = ?14,"
671 " crop = ?15, orientation = ?16, raw_parameters = ?17, group_id = ?18,"
672 " longitude = ?19, latitude = ?20, altitude = ?21, color_matrix = ?22,"
673 " colorspace = ?23, raw_black = ?24, raw_maximum = ?25,"
674 " aspect_ratio = ROUND(?26,1), exposure_bias = ?27,"
675 " import_timestamp = ?28, change_timestamp = ?29, export_timestamp = ?30,"
676 " print_timestamp = ?31, output_width = ?32, output_height = ?33"
677 " WHERE id = ?34",
678 -1, &stmt, NULL);
679 // clang-format on
680 DT_DEBUG_SQLITE3_BIND_INT(stmt, 1, img->width);
681 DT_DEBUG_SQLITE3_BIND_INT(stmt, 2, img->height);
682 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 3, img->filename, -1, SQLITE_STATIC);
683 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 4, img->exif_maker, -1, SQLITE_STATIC);
684 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 5, img->exif_model, -1, SQLITE_STATIC);
685 DT_DEBUG_SQLITE3_BIND_TEXT(stmt, 6, img->exif_lens, -1, SQLITE_STATIC);
691 DT_DEBUG_SQLITE3_BIND_INT(stmt, 12, img->film_id);
692 if(img->exif_datetime_taken)
694 DT_DEBUG_SQLITE3_BIND_INT(stmt, 14, img->flags);
697 flip.s = img->legacy_flip;
698 DT_DEBUG_SQLITE3_BIND_INT(stmt, 17, flip.u);
699 DT_DEBUG_SQLITE3_BIND_INT(stmt, 18, img->group_id);
703 DT_DEBUG_SQLITE3_BIND_BLOB(stmt, 22, &img->d65_color_matrix, sizeof(img->d65_color_matrix), SQLITE_STATIC);
707 DT_DEBUG_SQLITE3_BIND_DOUBLE(stmt, 26, 0.); // img->aspect_ratio deprecated
709 if(img->import_timestamp)
711 if(img->change_timestamp)
713 if(img->export_timestamp)
715 if(img->print_timestamp)
717 DT_DEBUG_SQLITE3_BIND_INT(stmt, 32, 0); // img->final_width deprecated
718 DT_DEBUG_SQLITE3_BIND_INT(stmt, 33, 0); // img->final_height deprecated
719 DT_DEBUG_SQLITE3_BIND_INT(stmt, 34, img->id);
720 const int rc = sqlite3_step(stmt);
721 if(rc != SQLITE_DONE) fprintf(stderr, "[image_cache_write_release] sqlite3 error %d\n", rc);
722 sqlite3_finalize(stmt);
723
726
727 const int32_t imgid = img->id;
728 dt_cache_release(&cache->cache, img->cache_entry);
729
731 dt_control_save_xmp(imgid);
732
733 // FIXME: that a memory leak ?
734 GList *imgs = NULL;
735 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img->id));
737}
738
739
740// remove the image from the cache
741void dt_image_cache_remove(dt_image_cache_t *cache, const int32_t imgid)
742{
743 dt_cache_remove(&cache->cache, imgid);
744}
745
747{
748 if(imgid <= 0) return;
749 dt_image_t *img = dt_image_cache_get(cache, imgid, 'w');
750 if(IS_NULL_PTR(img)) return;
753}
754
756{
757 if(imgid <= 0) return;
758 dt_image_t *img = dt_image_cache_get(cache, imgid, 'w');
759 if(IS_NULL_PTR(img)) return;
762}
763
764// clang-format off
765// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
766// vim: shiftwidth=2 expandtab tabstop=2 cindent
767// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
768// clang-format on
#define FALSE
Definition ashift_lsd.c:158
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
void dt_colorlabels_set_labels(const int32_t imgid, const int colors)
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
#define dt_cache_release(A, B)
#define dt_cache_get(A, B, C)
static void dt_cache_set_cleanup_callback(dt_cache_t *cache, dt_cache_cleanup_t cleanup_cb, void *cleanup_data)
static void dt_cache_set_allocate_callback(dt_cache_t *cache, dt_cache_allocate_t allocate_cb, void *allocate_data)
void dt_image_refresh_makermodel(dt_image_t *img)
int dt_image_monochrome_flags(const dt_image_t *img)
gboolean dt_image_is_hdr(const dt_image_t *img)
void dt_image_init(dt_image_t *img)
const char * dt_image_film_roll_name(const char *path)
gboolean dt_image_use_monochrome_workflow(const dt_image_t *img)
int dt_image_get_xmp_rating_from_flags(const int flags)
gboolean dt_image_get_xmp_mode()
void dt_image_set_provisional_dsc(dt_image_t *img)
void dt_image_local_copy_paths_from_fullpath(const char *fullpath, int32_t imgid, char *local_copy_path, size_t local_copy_len, char *local_copy_legacy_path, size_t local_copy_legacy_len)
char * key
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
void dt_control_save_xmp(const int32_t imgid)
darktable_t darktable
Definition darktable.c:183
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_CACHE
Definition darktable.h:737
@ DT_DEBUG_IMAGEIO
Definition darktable.h:755
static void dt_free_gpointer(gpointer ptr)
Definition darktable.h:485
#define dt_free(ptr)
Definition darktable.h:478
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition darktable.h:1123
static const dt_aligned_pixel_simd_t value
Definition darktable.h:599
#define DT_MAX_FILENAME_LEN
Definition darktable.h:1179
#define PATH_MAX
Definition darktable.h:1189
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
Definition darktable.h:293
sqlite3 * dt_database_get(const dt_database_t *db)
Definition database.c:3653
gboolean dt_datetime_gtimespan_to_local(char *local, const size_t local_size, const GTimeSpan gts, const gboolean msec, const gboolean tz)
Definition datetime.c:164
GTimeSpan dt_datetime_now_to_gtimespan()
Definition datetime.c:223
#define DT_DEBUG_SQLITE3_BIND_BLOB(a, b, c, d, e)
Definition debug.h:119
#define DT_DEBUG_SQLITE3_PREPARE_V2(a, b, c, d, e)
Definition debug.h:107
#define DT_DEBUG_SQLITE3_BIND_TEXT(a, b, c, d, e)
Definition debug.h:118
#define DT_DEBUG_SQLITE3_BIND_INT(a, b, c)
Definition debug.h:115
#define DT_DEBUG_SQLITE3_BIND_INT64(a, b, c)
Definition debug.h:116
#define DT_DEBUG_SQLITE3_BIND_DOUBLE(a, b, c)
Definition debug.h:117
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:384
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:369
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:389
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
dt_image_colorspace_t
Definition image.h:178
dt_image_orientation_t
Definition image.h:203
dt_image_flags_t
Definition image.h:91
@ DT_IMAGE_HAS_WAV
Definition image.h:125
@ DT_IMAGE_LOCAL_COPY
Definition image.h:121
@ DT_IMAGE_RAW
Definition image.h:111
@ DT_IMAGE_HDR
Definition image.h:113
@ DT_IMAGE_LDR
Definition image.h:109
static dt_pthread_mutex_t _image_cache_stmt_mutex
Definition image_cache.c:64
void dt_image_cache_cleanup(dt_image_cache_t *cache)
void dt_image_cache_init(dt_image_cache_t *cache)
static sqlite3_stmt * _image_cache_write_history_hash_stmt
Definition image_cache.c:63
static uint64_t _image_cache_self_hash(const dt_image_t *img)
Definition image_cache.c:76
static void _image_cache_write_history_hash(const dt_image_t *img)
static gsize _image_cache_stmt_mutex_inited
Definition image_cache.c:65
void dt_image_cache_read_release(dt_image_cache_t *cache, const dt_image_t *img)
void dt_image_cache_get_usage(dt_image_cache_t *cache, size_t *current, size_t *max)
dt_image_t * dt_image_cache_get_reload(dt_image_cache_t *cache, const int32_t imgid, char mode)
void dt_image_cache_allocate(void *data, dt_cache_entry_t *entry)
static sqlite3_stmt * _image_cache_load_stmt
Definition image_cache.c:62
dt_image_t * dt_image_cache_get(dt_image_cache_t *cache, const int32_t imgid, char mode)
int dt_image_cache_seed(dt_image_cache_t *cache, const dt_image_t *img)
static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid, const dt_sv_op_t sv_op)
static void _image_cache_lock_init(dt_image_t *img)
static void _image_cache_info_changed_reload_callback(gpointer instance, gpointer imgs, gpointer user_data)
void dt_image_cache_set_export_timestamp(dt_image_cache_t *cache, const int32_t imgid)
int dt_image_invalid(const dt_image_t *img)
void dt_image_cache_write_release(dt_image_cache_t *cache, dt_image_t *img, dt_image_cache_write_mode_t mode)
void dt_image_cache_remove(dt_image_cache_t *cache, const int32_t imgid)
void dt_image_from_stmt(dt_image_t *img, sqlite3_stmt *stmt)
void dt_image_cache_deallocate(void *data, dt_cache_entry_t *entry)
void dt_image_cache_connect_info_changed_first(const struct dt_control_signal_t *ctlsig)
GArray * dt_image_cache_get_entries_stats(dt_image_cache_t *cache)
dt_image_t * dt_image_cache_testget(dt_image_cache_t *cache, const int32_t imgid, char mode)
static sqlite3_stmt * _image_cache_get_stmt(void)
void dt_image_cache_set_print_timestamp(dt_image_cache_t *cache, const int32_t imgid)
static void _image_cache_stmt_mutex_ensure(void)
Definition image_cache.c:67
void dt_image_cache_print(dt_image_cache_t *cache)
dt_image_cache_write_mode_t
Definition image_cache.h:47
@ DT_IMAGE_CACHE_MINIMAL
Definition image_cache.h:54
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:49
dt_image_flags_t dt_imageio_get_type_from_extension(const char *extension)
Map Exiv2 preview MIME types to decoder format identifiers.
Definition imageio.c:181
const char * maker
const char * model
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:460
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:366
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:144
int dt_cache_seed(dt_cache_t *cache, const uint32_t key, const void *data, size_t data_size, size_t cost, gboolean aligned_alloc)
dt_cache_entry_t * dt_cache_testget(dt_cache_t *cache, const uint32_t key, char mode)
void dt_cache_init(dt_cache_t *cache, size_t entry_size, size_t cost_quota)
int dt_cache_remove(dt_cache_t *cache, const uint32_t key)
void dt_cache_cleanup(dt_cache_t *cache)
const float const int flip
unsigned __int64 uint64_t
Definition strptime.c:75
const struct dt_database_t * db
Definition darktable.h:807
struct dt_control_signal_t * signals
Definition darktable.h:802
struct dt_image_cache_t * image_cache
Definition darktable.h:805
uint32_t key
size_t data_size
int _lock_demoting
void * data
size_t cost
size_t cost
size_t cost_quota
GHashTable * hashtable
dt_pthread_mutex_t lock
Definition image_cache.h:64
char filename[128]
Definition image_cache.h:67
size_t size
Definition image_cache.h:66
int32_t imgid
Definition image_cache.h:65
dt_cache_t cache
Definition image_cache.h:40
double latitude
Definition image.h:275
double elevation
Definition image.h:275
double longitude
Definition image.h:275
gboolean has_audio
Definition image.h:375
gboolean is_hdr
Definition image.h:378
float exif_exposure
Definition image.h:285
int32_t height
Definition image.h:315
GTimeSpan export_timestamp
Definition image.h:333
uint64_t history_hash
Definition image.h:322
float exif_focus_distance
Definition image.h:290
GTimeSpan import_timestamp
Definition image.h:333
gboolean is_bw
Definition image.h:376
int32_t group_id
Definition image.h:319
float exif_exposure_bias
Definition image.h:286
uint16_t raw_black_level
Definition image.h:350
float exif_iso
Definition image.h:288
GList * dng_gain_maps
Definition image.h:368
uint32_t raw_white_point
Definition image.h:352
int32_t exif_inited
Definition image.h:283
float exif_aperture
Definition image.h:287
int32_t version
Definition image.h:319
int32_t crop_height
Definition image.h:316
uint64_t mipmap_hash
Definition image.h:329
char fullpath[PATH_MAX]
Definition image.h:305
dt_image_geoloc_t geoloc
Definition image.h:347
int32_t flags
Definition image.h:319
dt_image_orientation_t orientation
Definition image.h:284
int32_t width
Definition image.h:315
float exif_focal_length
Definition image.h:289
char exif_maker[64]
Definition image.h:292
GTimeSpan change_timestamp
Definition image.h:333
uint32_t profile_size
Definition image.h:341
int32_t crop_y
Definition image.h:316
uint32_t history_items
Definition image.h:321
int rating
Definition image.h:372
gboolean has_localcopy
Definition image.h:374
char exif_lens[128]
Definition image.h:294
char local_copy_path[PATH_MAX]
Definition image.h:306
GTimeSpan print_timestamp
Definition image.h:333
int32_t film_id
Definition image.h:319
GTimeSpan exif_datetime_taken
Definition image.h:295
int32_t crop_x
Definition image.h:316
int color_labels
Definition image.h:371
float d65_color_matrix[9]
Definition image.h:339
char exif_model[64]
Definition image.h:293
dt_image_colorspace_t colorspace
Definition image.h:342
uint8_t * profile
Definition image.h:340
char datetime[200]
Definition image.h:310
struct dt_cache_entry_t * cache_entry
Definition image.h:381
int32_t crop_width
Definition image.h:316
uint32_t group_members
Definition image.h:320
dt_image_raw_parameters_t legacy_flip
Definition image.h:344
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:304
char folder[PATH_MAX]
Definition image.h:308
int32_t id
Definition image.h:319
char filmroll[PATH_MAX]
Definition image.h:309
uint64_t self_hash
Definition image.h:330
char local_copy_legacy_path[PATH_MAX]
Definition image.h:307
float exif_crop
Definition image.h:291
gboolean is_bw_flow
Definition image.h:377
void dt_supervisor_image(const dt_sv_op_t op, const int32_t imgid, const dt_image_t *img)
dt_sv_op_t
Definition supervisor.h:76
@ DT_SV_UPDATE
Definition supervisor.h:78
@ DT_SV_CREATE
Definition supervisor.h:77
@ DT_SV_DELETE
Definition supervisor.h:80
static gboolean dt_supervisor_active(void)
Definition supervisor.h:94
@ DT_VIEW_REJECT
Definition view.h:175