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
44#include "caches/image_cache.h"
45#include "system/macros.h"
46#include "system/mem_alloc.h"
47#include "common/hash.h"
48#include "common/logging.h"
49#include "common/paths.h"
50#include "common/image.h"
51#include "common/datetime.h"
52#include "control/control.h"
53#include "control/signal.h"
54#include "develop/supervisor.h"
55
56#include <inttypes.h>
57#include "colorprofiles/colorspaces.h" // dt_colorspaces_free_image_profile
58
59/* Set once by dt_image_cache_init(); see the header for why it is not read live. */
60static gboolean _verbose = FALSE;
61
62/* Statement-safe: a bare `if(_verbose) dt_print(...)` swallows a following `else`. */
63#define _cache_print(channel, ...) \
64 do { \
65 if(_verbose) dt_print((channel), __VA_ARGS__); \
66 } while(0)
67
68
69/* PRIVATE. Nothing outside this file reads a field of it -- the header exposes the
70 * type as an opaque handle so that it cannot. */
71typedef struct dt_image_cache_t
72{
74}
76
77
78/* The cache instance, owned HERE. It used to be calloc'd by darktable.c and hung off the
79 * application struct, so the accessor lived in the orchestrator and the struct was reachable
80 * from anything that included darktable.h. */
82
84{
86}
87
88
89
91{
92 if(IS_NULL_PTR(img) || img->id <= 0) return 0;
93
94 struct
95 {
96 dt_image_orientation_t orientation;
97 float exif_exposure;
98 float exif_exposure_bias;
99 float exif_aperture;
100 float exif_iso;
101 float exif_focal_length;
102 float exif_focus_distance;
103 float exif_crop;
104 char exif_maker[64];
105 char exif_model[64];
106 char exif_lens[128];
107 GTimeSpan exif_datetime_taken;
108 char filename[DT_MAX_FILENAME_LEN];
109 int32_t width, height;
110 int32_t crop_x, crop_y, crop_width, crop_height;
111 int32_t flags, film_id, id, group_id, version;
112 uint64_t history_hash;
113 float d65_color_matrix[9];
114 dt_image_colorspace_t colorspace;
115 dt_image_raw_parameters_t legacy_flip;
116 dt_image_geoloc_t geoloc;
117 uint16_t raw_black_level;
118 uint32_t raw_white_point;
119 int color_labels;
120 } persisted = { 0 };
121
122 /*
123 * Track only the dt_image_t fields that are explicitly written back to the database
124 * from dt_image_cache_write_release(), plus the history hash and color labels that
125 * are flushed through their own SQL paths right below it. Runtime-only fields such
126 * as cached ICC pointers, DNG gain-map lists, loader state or derived path strings
127 * must stay out of this hash, otherwise merely opening an image can look like an
128 * edit and spuriously bump change_timestamp.
129 */
130 persisted.orientation = img->orientation;
131 persisted.exif_exposure = img->exif_exposure;
132 persisted.exif_exposure_bias = img->exif_exposure_bias;
133 persisted.exif_aperture = img->exif_aperture;
134 persisted.exif_iso = img->exif_iso;
135 persisted.exif_focal_length = img->exif_focal_length;
136 persisted.exif_focus_distance = img->exif_focus_distance;
137 persisted.exif_crop = img->exif_crop;
138 memcpy(persisted.exif_maker, img->exif_maker, sizeof(persisted.exif_maker));
139 memcpy(persisted.exif_model, img->exif_model, sizeof(persisted.exif_model));
140 memcpy(persisted.exif_lens, img->exif_lens, sizeof(persisted.exif_lens));
141 persisted.exif_datetime_taken = img->exif_datetime_taken;
142 memcpy(persisted.filename, img->filename, sizeof(persisted.filename));
143 persisted.width = img->width;
144 persisted.height = img->height;
145 persisted.crop_x = img->crop_x;
146 persisted.crop_y = img->crop_y;
147 persisted.crop_width = img->crop_width;
148 persisted.crop_height = img->crop_height;
149 persisted.flags = img->flags;
150 persisted.film_id = img->film_id;
151 persisted.id = img->id;
152 persisted.group_id = img->group_id;
153 persisted.version = img->version;
154 persisted.history_hash = img->history_hash;
155 memcpy(persisted.d65_color_matrix, img->d65_color_matrix, sizeof(persisted.d65_color_matrix));
156 persisted.colorspace = img->colorspace;
157 persisted.legacy_flip = img->legacy_flip;
158 persisted.geoloc = img->geoloc;
159 persisted.raw_black_level = img->raw_black_level;
160 persisted.raw_white_point = img->raw_white_point;
161 persisted.color_labels = img->color_labels;
162
163 return dt_hash(5381, (const char *)&persisted, sizeof(persisted));
164}
165
166static inline void _image_cache_lock_init(dt_image_t *img)
167{
169}
170
171
172
173
174/* Fields the database does not store because they are computed from the ones it does:
175 * the rating, the monochrome and HDR predicates, the extension cross-check, makermodel.
176 * They live here rather than in database/image_repository.c because they need
177 * imageio/ and views/ symbols, and a row mapper reaching two layers up for them is exactly
178 * what kept this code in common/. Every path that produces a dt_image_t from a database row
179 * calls this next -- the repository's own load, and gui/dtgtk/thumbtable.c's bulk query. */
181{
182 if(IS_NULL_PTR(img)) return;
184 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
185 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
186 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
189 img->is_hdr = dt_image_is_hdr(img);
190
191 // Instrumentation: the LDR/HDR flags are now pure flag predicates (no filename sniffing at read
192 // time). Historically the flag could have been mis-set at import, so cross-check the flags loaded
193 // from the DB against the unambiguous extension hint and log any contradiction. Containers whose
194 // dynamic range only the decoder can settle (TIFF/AVIF/HEIF/DNG ...) return 0 here and are skipped
195 // to avoid false positives. This surfaces stale/garbage flags persisted in the database.
196 {
197 const gchar *ext = g_strrstr(img->filename, ".");
198 const dt_image_flags_t ext_hint = ext ? dt_image_flags_from_extension(ext) : 0;
199 const gboolean db_hdr = (img->flags & DT_IMAGE_HDR) != 0;
200 const gboolean db_ldr = (img->flags & DT_IMAGE_LDR) != 0;
201
202 if(ext_hint == DT_IMAGE_HDR && !db_hdr)
204 "[image_cache] DB flag mismatch: id=%d filename='%s' has an HDR extension but stored "
205 "flags=0x%08x lack DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
206 img->id, img->filename, (unsigned int)img->flags, db_ldr, db_hdr);
207 else if((ext_hint == DT_IMAGE_LDR || ext_hint == DT_IMAGE_RAW) && db_hdr)
209 "[image_cache] DB flag mismatch: id=%d filename='%s' has a %s extension but stored "
210 "flags=0x%08x carry DT_IMAGE_HDR (ldr=%d hdr=%d)\n",
211 img->id, img->filename, (ext_hint == DT_IMAGE_RAW) ? "RAW" : "LDR",
212 (unsigned int)img->flags, db_ldr, db_hdr);
213 }
214
216}
217
218static void _image_cache_reload_from_db(dt_image_t *img, const uint32_t imgid, const dt_sv_op_t sv_op)
219{
220 dt_image_repository_load((int32_t)imgid, img);
222
223 // The image's dt_image_t was just (re)loaded from the database: `create` on
224 // first allocation, `update` on a reload (get_reload / IMAGE_INFO_CHANGED).
225 // Notifying is the cache's job, not the repository's -- the repository does not
226 // know what a supervisor is.
227 if(dt_supervisor_active()) dt_supervisor_image(sv_op, (int32_t)imgid, img);
228}
229
231{
232 entry->cost = sizeof(dt_image_t);
233
234 // dt_alloc_align: dt_image_t embeds dt_aligned_pixel_t members (alignof 64); see #1212.
236 entry->data = img;
237 dt_image_init(img);
238 _image_cache_reload_from_db(img, entry->key, DT_SV_CREATE); // emits the create event
239
240 img->cache_entry = entry; // init backref
241}
242
244{
245 dt_image_t *img = (dt_image_t *)entry->data;
246
247 if(dt_supervisor_active()) dt_supervisor_image(DT_SV_DELETE, (int32_t)entry->key, NULL);
248
249 dt_free(img->profile);
251 img->embedded_profile = NULL;
252 g_list_free_full(img->dng_gain_maps, dt_free_gpointer);
253 img->dng_gain_maps = NULL;
254 dt_free_align(img);
255}
256
257void dt_image_cache_init(const gboolean verbose)
258{
259 _verbose = verbose;
260 if(_image_cache) return;
261 _image_cache = (dt_image_cache_t *)calloc(1, sizeof(dt_image_cache_t));
262 if(IS_NULL_PTR(_image_cache)) return;
264 // the image cache does no serialization.
265 // (unsafe. data should be in db/xmp, not in any other additional cache,
266 // also, it should be relatively fast to get the image_t structs from sql.)
267 // TODO: actually an independent conf var?
268 // too large: dangerous and wasteful?
269 // can we get away with a fixed size?
270 const uint32_t size = 50;
271 const uint32_t max_mem = size * 1024 * 1024;
272 const uint32_t num = (uint32_t)(1.5f * max_mem / sizeof(dt_image_t));
273 dt_cache_init(&cache->cache, sizeof(dt_image_t), max_mem);
276
277 _cache_print(DT_DEBUG_CACHE, "[image_cache] has %d entries (%u MiB)\n", num, size);
278}
279
281{
283 if(IS_NULL_PTR(cache)) return;
285
286 dt_cache_cleanup(&cache->cache);
287
289 _image_cache = NULL;
290}
291
293{
294 const dt_image_cache_t *const cache = _image_cache;
295 printf("[image cache] fill %.2f/%.2f MB (%.2f%%)\n", cache->cache.cost / (1024.0 * 1024.0),
296 cache->cache.cost_quota / (1024.0 * 1024.0),
297 (float)cache->cache.cost / (float)cache->cache.cost_quota);
298}
299
300void dt_image_cache_get_usage(size_t *current, size_t *max)
301{
303 if(current) *current = 0;
304 if(max) *max = 0;
305 if(IS_NULL_PTR(cache)) return;
307 if(current) *current = cache->cache.cost;
308 if(max) *max = cache->cache.cost_quota;
310}
311
313{
315 GArray *out = g_array_new(FALSE, FALSE, sizeof(dt_image_cache_stats_entry_t));
316 if(IS_NULL_PTR(cache)) return out;
317
319 GHashTableIter it;
320 gpointer key, value;
321 g_hash_table_iter_init(&it, cache->cache.hashtable);
322 while(g_hash_table_iter_next(&it, &key, &value))
323 {
324 const dt_cache_entry_t *ce = (const dt_cache_entry_t *)value;
325 if(IS_NULL_PTR(ce)) continue;
327 s.imgid = (int32_t)ce->key;
328 s.size = ce->cost ? ce->cost : ce->data_size;
329 const dt_image_t *img = (const dt_image_t *)ce->data;
330 if(img && img->filename[0]) g_strlcpy(s.filename, img->filename, sizeof(s.filename));
331 g_array_append_val(out, s);
332 }
334 return out;
335}
336
337dt_image_t *dt_image_cache_get(const int32_t imgid, char mode)
338{
340 if(imgid <= 0) return NULL;
341 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, mode);
343 dt_image_t *img = (dt_image_t *)entry->data;
344 img->cache_entry = entry;
345
346 if(dt_image_invalid(img))
347 {
348 dt_cache_release(&cache->cache, entry);
349 return NULL;
350 }
351
353 return img;
354}
355
356dt_image_t *dt_image_cache_testget(const int32_t imgid, char mode)
357{
359 if(imgid <= 0) return NULL;
360 dt_cache_entry_t *entry = dt_cache_testget(&cache->cache, (uint32_t)imgid, mode);
361 if(IS_NULL_PTR(entry)) return 0;
363 dt_image_t *img = (dt_image_t *)entry->data;
364 img->cache_entry = entry;
365
366 /* Same contract as dt_image_cache_get() and dt_image_cache_get_reload(): an entry whose row
367 * has gone stays in the cache with id == UNKNOWN_IMAGE, and handing it out LOCKED is how the
368 * lock leaks -- the caller has no way to release what it was told was not an image. */
369 if(dt_image_invalid(img))
370 {
371 dt_cache_release(&cache->cache, entry);
372 return NULL;
373 }
374
376 return img;
377}
378
379dt_image_t *dt_image_cache_get_existing(const int32_t imgid, char mode)
380{
382 if(imgid <= 0) return NULL;
383
384 // contains() answers "is there an entry" without taking the entry's lock, which is the one
385 // question testget() conflates with "is it free right now"
386 if(!dt_cache_contains(&cache->cache, (uint32_t)imgid)) return NULL;
387 return dt_image_cache_get(imgid, mode);
388}
389
390// Always reload the cache entry from DB before returning it.
391// This is critical for IMAGE_INFO_CHANGED: other handlers will read from the cache.
392dt_image_t *dt_image_cache_get_reload(const int32_t imgid, char mode)
393{
395 if(imgid <= 0) return NULL;
396
397 // We must take a write lock to reload in-place, then demote to read if requested.
398 dt_cache_entry_t *entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'w');
400 dt_image_t *img = (dt_image_t *)entry->data;
401 _image_cache_reload_from_db(img, (uint32_t)imgid, DT_SV_UPDATE);
402
403 img->cache_entry = entry;
404
405 if(dt_image_invalid(img))
406 {
407 dt_cache_release(&cache->cache, entry);
408 return NULL;
409 }
410
411 if(mode == 'r')
412 {
413 // demote the lock to read mode (see mipmap cache for rationale)
414 entry->_lock_demoting = 1;
415 dt_cache_release(&cache->cache, entry);
416 entry = dt_cache_get(&cache->cache, (uint32_t)imgid, 'r');
417 entry->_lock_demoting = 0;
419 img = (dt_image_t *)entry->data;
420 img->cache_entry = entry;
421 }
422
424 return img;
425}
426
428{
429 return (IS_NULL_PTR(img) || img->id <= 0);
430}
431
433{
435 if(IS_NULL_PTR(cache) || dt_image_invalid(img)) return -1;
436
437 dt_image_t seeded = *img;
438
439 // Avoid ownership issues for pointers that the cache cleanup would free.
440 seeded.profile = NULL;
441 seeded.profile_size = 0;
442 seeded.dng_gain_maps = NULL;
443 seeded.cache_entry = NULL;
444
445 // dt_image_cache_deallocate() frees entry->data with dt_free_align(); dt_cache_seed()
446 // allocates with dt_alloc_align() and no longer offers any other option.
447 return dt_cache_seed(&cache->cache, (uint32_t)seeded.id, &seeded, sizeof(dt_image_t), sizeof(dt_image_t));
448}
449
450// This callback must run before any other DT_SIGNAL_IMAGE_INFO_CHANGED handler.
451// The signal notifies about DB changes, and most listeners read image info from the cache.
452// We therefore force a DB reload here so every subsequent handler sees up-to-date data.
453static void _image_cache_info_changed_reload_callback(gpointer instance, gpointer imgs, gpointer user_data)
454{
455 for(GList *l = g_list_first((GList *)imgs); l; l = g_list_next(l))
456 {
457 const int32_t imgid = GPOINTER_TO_INT(l->data);
458 if(imgid <= 0) continue;
459
460 dt_image_t *img = dt_image_cache_get_reload(imgid, 'r');
461 if(img)
463 }
464}
465
467{
468 // Must be connected early to run before any other handler.
471}
472
473// drops the read lock on an image struct
475{
477 if(IS_NULL_PTR(img)) return;
478
479 /* What is being returned is the LOCK, not the image, so an entry whose row has gone in the
480 * meantime is released like any other. The guard used to read `|| img->id <= 0` -- which is
481 * dt_image_invalid() spelled out -- and that silently skipped the release for exactly the
482 * entries most likely to have one outstanding, deadlocking the next writer for good. */
483 if(dt_image_invalid(img))
484 {
485 if(!IS_NULL_PTR(img->cache_entry)) dt_cache_release(&cache->cache, img->cache_entry);
486 return;
487 }
488
489 const uint64_t self_hash = _image_cache_self_hash(img);
490 if(self_hash != img->self_hash)
491 g_error("[image_cache] read lock modified image %d, you need to use a write lock\n", img->id);
492
493 // just force the dt_image_t struct to make sure it has been locked before.
494 dt_cache_release(&cache->cache, img->cache_entry);
495}
496
497// drops the write privileges on an image struct.
498// this triggers a write-through to sql, and optionally queues xmp sidecar writing.
500{
502 if(IS_NULL_PTR(img)) return;
503
504 // same as the read side: release the lock, write nothing back for a row that is gone
505 if(dt_image_invalid(img))
506 {
507 if(!IS_NULL_PTR(img->cache_entry)) dt_cache_release(&cache->cache, img->cache_entry);
508 return;
509 }
510
511 const uint64_t self_hash = _image_cache_self_hash(img);
512 const gboolean changed = (self_hash != img->self_hash);
513
514 if(changed)
516
517 // even if nothing changed, we might need to write export/print timestamps
518 // and mipmap hash, so we can't exit just yet.
519
520 if(mode == DT_IMAGE_CACHE_MINIMAL)
521 {
522 if(changed)
523 g_error("[image_cache] minimal write release modified image %d, you need to commit those changes to DB.\n", img->id);
524
525 dt_cache_release(&cache->cache, img->cache_entry);
526 return;
527 }
528
529 // Recompute full/local copy paths (and derived folder/filmroll/datetime) from possibly updated filename.
530 // Avoid SQL here; rely on the cached folder/fullpath, or leave fields empty if they can't be rebuilt.
531 char folder[DT_PATH_MAX] = { 0 };
532 if(img->folder[0])
533 {
534 g_strlcpy(folder, img->folder, sizeof(folder));
535 }
536 else if(img->fullpath[0])
537 {
538 gchar *dir = g_path_get_dirname(img->fullpath);
539 if(dir && dir[0] && strcmp(dir, "."))
540 g_strlcpy(folder, dir, sizeof(folder));
541 dt_free(dir);
542 }
543
544 if(img->filename[0] && folder[0])
545 {
546 g_snprintf(img->fullpath, sizeof(img->fullpath), "%s" G_DIR_SEPARATOR_S "%s", folder, img->filename);
547 g_strlcpy(img->folder, folder, sizeof(img->folder));
548 }
549 else
550 {
551 img->fullpath[0] = '\0';
552 img->folder[0] = '\0';
553 }
554 if(img->folder[0])
555 g_strlcpy(img->filmroll, dt_image_film_roll_name(img->folder), sizeof(img->filmroll));
556 else if(img->film_id < 0)
557 g_strlcpy(img->filmroll, _("orphaned image"), sizeof(img->filmroll));
558 else
559 img->filmroll[0] = '\0';
562 sizeof(img->local_copy_path), img->local_copy_legacy_path,
563 sizeof(img->local_copy_legacy_path));
564
566 img->has_audio = (img->flags & DT_IMAGE_HAS_WAV);
567 int xmp_rating = dt_image_get_xmp_rating_from_flags(img->flags);
568 img->rating = (xmp_rating == -1) ? DT_VIEW_REJECT : xmp_rating;
571 img->is_hdr = dt_image_is_hdr(img);
572
574
575 const int32_t imgid = img->id;
576 dt_cache_release(&cache->cache, img->cache_entry);
577
579 dt_control_save_xmp(imgid);
580
581 // FIXME: that a memory leak ?
582 GList *imgs = NULL;
583 imgs = g_list_prepend(imgs, GINT_TO_POINTER(img->id));
585}
586
587
588// remove the image from the cache
589void dt_image_cache_remove(const int32_t imgid)
590{
592 dt_cache_remove(&cache->cache, imgid);
593}
594
595void dt_image_cache_set_export_timestamp(const int32_t imgid)
596{
597 if(imgid <= 0) return;
598 dt_image_t *img = dt_image_cache_get(imgid, 'w');
599 if(IS_NULL_PTR(img)) return;
602}
603
604void dt_image_cache_set_print_timestamp(const int32_t imgid)
605{
606 if(imgid <= 0) return;
607 dt_image_t *img = dt_image_cache_get(imgid, 'w');
608 if(IS_NULL_PTR(img)) return;
611}
612
613// clang-format off
614// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
615// vim: shiftwidth=2 expandtab tabstop=2 cindent
616// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
617// clang-format on
#define FALSE
Definition ashift_lsd.c:158
#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_colorspaces_free_image_profile(struct dt_colorspaces_color_profile_t *profile)
Release a profile container owned by an image, closing the LCMS2 handle inside it if and only if the ...
The colour-profile module's API: which profiles exist, and how to apply one.
const float max
const dt_colormatrix_t dt_aligned_pixel_t out
dt_image_flags_t dt_image_flags_from_extension(const char *extension)
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_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)
#define ASAN_UNPOISON_MEMORY_REGION(addr, size)
void dt_control_save_xmp(const int32_t imgid)
void * dt_alloc_align(size_t size)
Allocate cacheline-aligned memory.
Definition darktable.c:508
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:178
GTimeSpan dt_datetime_now_to_gtimespan()
Definition datetime.c:237
GtkWidget * folder
destination folder chooser
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:127
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
static uint64_t dt_hash(uint64_t hash, const char *str, size_t size)
Definition hash.h:55
dt_image_colorspace_t
Definition image.h:191
dt_image_orientation_t
Definition image.h:216
dt_image_flags_t
Definition image.h:104
@ DT_IMAGE_HAS_WAV
Definition image.h:138
@ DT_IMAGE_LOCAL_COPY
Definition image.h:134
@ DT_IMAGE_RAW
Definition image.h:124
@ DT_IMAGE_HDR
Definition image.h:126
@ DT_IMAGE_LDR
Definition image.h:122
@ DT_VIEW_REJECT
Definition image.h:355
static dt_image_cache_t * _image_cache
Definition image_cache.c:81
void dt_image_cache_set_print_timestamp(const int32_t imgid)
dt_image_t * dt_image_cache_get_existing(const int32_t imgid, char mode)
void dt_image_cache_write_release(dt_image_t *img, dt_image_cache_write_mode_t mode)
static uint64_t _image_cache_self_hash(const dt_image_t *img)
Definition image_cache.c:90
dt_image_t * dt_image_cache_testget(const int32_t imgid, char mode)
gboolean dt_image_cache_is_ready(void)
Has the image cache been initialised? Callers that run before dt_image_cache_init() or after its clea...
Definition image_cache.c:83
void dt_image_cache_get_usage(size_t *current, size_t *max)
GArray * dt_image_cache_get_entries_stats(void)
static gboolean _verbose
Definition image_cache.c:60
void dt_image_cache_set_export_timestamp(const int32_t imgid)
#define _cache_print(channel,...)
Definition image_cache.c:63
void dt_image_cache_allocate(void *data, dt_cache_entry_t *entry)
void dt_image_cache_init(const gboolean verbose)
Initialise the cache.
void dt_image_derive_fields(dt_image_t *img)
Compute the fields the database does not store: rating, monochrome and HDR predicates,...
dt_image_t * dt_image_cache_get(const int32_t imgid, char mode)
dt_image_t * dt_image_cache_get_reload(const int32_t imgid, char mode)
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)
int dt_image_invalid(const dt_image_t *img)
int dt_image_cache_seed(const dt_image_t *img)
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)
void dt_image_cache_print(void)
void dt_image_cache_remove(const int32_t imgid)
void dt_image_cache_read_release(const dt_image_t *img)
void dt_image_cache_cleanup(void)
dt_image_cache_write_mode_t
Definition image_cache.h:46
@ DT_IMAGE_CACHE_MINIMAL
Definition image_cache.h:53
@ DT_IMAGE_CACHE_SAFE
Definition image_cache.h:48
void dt_image_repository_cleanup(void)
Finalise the prepared statements. Called at shutdown, after the last cache release and before the dat...
gboolean dt_image_repository_load(const int32_t imgid, dt_image_t *img)
Fill img from the main.images row for imgid.
void dt_image_repository_store(const dt_image_t *img)
Write img back to main.images, plus its colour labels and history hash.
Reading and writing one dt_image_t to and from the library database. The SQL half of what used to be ...
@ DT_DEBUG_CACHE
Definition logging.h:51
@ DT_DEBUG_IMAGEIO
Definition logging.h:68
#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 macros.h:96
#define dt_free_align(ptr)
Release memory from dt_alloc_align() and set ptr to NULL.
Definition mem_alloc.h:214
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
Definition mem_alloc.h:184
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
char * key
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
size_t size
Definition mipmap_cache.c:3
dt_mipmap_buffer_dsc_flags flags
Definition mipmap_cache.c:4
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
#define DT_MAX_FILENAME_LEN
Definition paths.h:35
void dt_control_signal_connect(const dt_control_signal_t *ctlsig, dt_signal_t signal, GCallback cb, gpointer user_data)
Definition signal.c:467
#define DT_DEBUG_CONTROL_SIGNAL_RAISE(ctlsig, signal,...)
Definition signal.h:386
struct dt_control_signal_t * dt_control_signal_get_global(void)
Definition darktable.c:616
@ DT_SIGNAL_IMAGE_INFO_CHANGED
This signal is raised when any of image info has changed
Definition signal.h:147
static const dt_aligned_pixel_simd_t value
Definition simd.h:144
int32_t dt_cache_contains(dt_cache_t *cache, const uint32_t key)
dt_cache_entry_t * dt_cache_testget(dt_cache_t *cache, const uint32_t key, char mode)
int dt_cache_seed(dt_cache_t *cache, const uint32_t key, const void *data, size_t data_size, size_t cost)
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)
unsigned __int64 uint64_t
Definition strptime.c:75
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:77
char filename[128]
Definition image_cache.h:80
size_t size
Definition image_cache.h:79
int32_t imgid
Definition image_cache.h:78
dt_cache_t cache
Definition image_cache.c:73
gboolean has_audio
Definition image.h:476
gboolean is_hdr
Definition image.h:479
float exif_exposure
Definition image.h:367
int32_t height
Definition image.h:397
GTimeSpan export_timestamp
Definition image.h:415
uint64_t history_hash
Definition image.h:404
float exif_focus_distance
Definition image.h:372
gboolean is_bw
Definition image.h:477
int32_t group_id
Definition image.h:401
float exif_exposure_bias
Definition image.h:368
uint16_t raw_black_level
Definition image.h:437
float exif_iso
Definition image.h:370
GList * dng_gain_maps
Definition image.h:464
uint32_t raw_white_point
Definition image.h:439
float exif_aperture
Definition image.h:369
char local_copy_path[DT_PATH_MAX]
Definition image.h:388
int32_t version
Definition image.h:401
int32_t crop_height
Definition image.h:398
dt_image_geoloc_t geoloc
Definition image.h:434
int32_t flags
Definition image.h:401
dt_image_orientation_t orientation
Definition image.h:366
int32_t width
Definition image.h:397
float exif_focal_length
Definition image.h:371
char exif_maker[64]
Definition image.h:374
GTimeSpan change_timestamp
Definition image.h:415
uint32_t profile_size
Definition image.h:423
int32_t crop_y
Definition image.h:398
int rating
Definition image.h:473
gboolean has_localcopy
Definition image.h:475
char exif_lens[128]
Definition image.h:376
GTimeSpan print_timestamp
Definition image.h:415
int32_t film_id
Definition image.h:401
char folder[DT_PATH_MAX]
Definition image.h:390
GTimeSpan exif_datetime_taken
Definition image.h:377
int32_t crop_x
Definition image.h:398
int color_labels
Definition image.h:472
float d65_color_matrix[9]
Definition image.h:421
char filmroll[DT_PATH_MAX]
Definition image.h:391
char exif_model[64]
Definition image.h:375
dt_image_colorspace_t colorspace
Definition image.h:429
struct dt_colorspaces_color_profile_t * embedded_profile
Definition image.h:428
uint8_t * profile
Definition image.h:422
char datetime[200]
Definition image.h:392
struct dt_cache_entry_t * cache_entry
Definition image.h:482
int32_t crop_width
Definition image.h:398
char local_copy_legacy_path[DT_PATH_MAX]
Definition image.h:389
dt_image_raw_parameters_t legacy_flip
Definition image.h:431
char filename[DT_MAX_FILENAME_LEN]
Definition image.h:386
int32_t id
Definition image.h:401
uint64_t self_hash
Definition image.h:412
float exif_crop
Definition image.h:373
char fullpath[DT_PATH_MAX]
Definition image.h:387
gboolean is_bw_flow
Definition image.h:478
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:77
@ DT_SV_UPDATE
Definition supervisor.h:79
@ DT_SV_CREATE
Definition supervisor.h:78
@ DT_SV_DELETE
Definition supervisor.h:81
static gboolean dt_supervisor_active(void)
Definition supervisor.h:95