Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
iop-autoset.c
Go to the documentation of this file.
1/*
2 This file is part of Ansel
3 Copyright (C) 2026 - Aurélien PIERRE
4
5 Ansel is free software: you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License, or
8 (at your option) any later version.
9
10 Ansel is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with darktable. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "iop-autoset.h"
20#include "develop/develop.h"
21#include "develop/pixelpipe.h"
24#include "develop/imageop.h"
25#include "control/conf.h"
26#include "control/control.h"
27
28#include <glib.h>
29
30static void _dt_iop_autoset_restart_cache_wait(gpointer user_data)
31{
32 dt_autoset_manager_t *manager = (dt_autoset_manager_t *)user_data;
33 if(IS_NULL_PTR(manager) || IS_NULL_PTR(manager->dev)) return;
34
35 dt_iop_autoset_advance(manager->dev, manager);
36}
37
38// Leave the busy cursor/progress state, exactly once.
40{
41 if(!IS_NULL_PTR(manager) && manager->progress_cursor_active)
42 {
45 }
46}
47
48// Tear down an autoset run: drop any pending cache-wait, clear the pipe flag
49// and release the busy cursor. Called whenever the queue can no longer be
50// processed (exhausted, or every remaining module went stale).
52 dt_dev_pixelpipe_cache_wait_t *input_wait, const char *reason)
53{
54 if(!IS_NULL_PTR(input_wait))
55 dt_dev_pixelpipe_cache_wait_cleanup(input_wait, reason);
56 if(!IS_NULL_PTR(pipe))
57 pipe->autoset = FALSE;
59}
60
61// Pop the next still-valid module off the queue, discarding stale entries.
62// The pipeline can be torn down and rebuilt between two advance() calls, so a
63// queued module pointer may dangle, get reused for a different module, or lose
64// its autoset callback. Re-validate against the live module list before use.
66{
67 GList *mod = g_list_first(manager->iop_to_set);
68 while(mod)
69 {
70 dt_iop_module_t *module = (dt_iop_module_t *)mod->data;
71 if(!IS_NULL_PTR(module) && g_list_find(dev->iop, module) && !IS_NULL_PTR(module->autoset))
72 return module;
73
74 // Stale entry: drop it and look at the next one.
75 manager->iop_to_set = g_list_delete_link(manager->iop_to_set, mod);
76 mod = g_list_first(manager->iop_to_set);
77 }
78 return NULL;
79}
80
82{
83 if(IS_NULL_PTR(module)) return NULL;
84 gchar *key = g_strdup_printf("plugins/darkroom/autoset/%s/%i", module->op, module->multi_priority);
85 return key;
86}
87
89{
90 gchar *key = dt_iop_autoset_get_conf_key(module);
91 if(IS_NULL_PTR(key)) return FALSE;
92
93 const gboolean enabled = !dt_conf_key_exists(key) || dt_conf_get_int(key) != 0;
94 g_free(key);
95 return enabled;
96}
97
98void dt_iop_autoset_module_set_enabled(const dt_iop_module_t *module, const gboolean enabled)
99{
100 gchar *key = dt_iop_autoset_get_conf_key(module);
101 if(IS_NULL_PTR(key)) return;
102
103 dt_conf_set_int(key, enabled ? 1 : 0);
104 g_free(key);
105}
106
108{
109 if(IS_NULL_PTR(dev) || IS_NULL_PTR(manager)) return;
110
111 if(IS_NULL_PTR(manager->input_wait))
112 manager->input_wait = g_malloc0(sizeof(dt_dev_pixelpipe_cache_wait_t));
114 "autoset-build-list-reset");
115
116 manager->dev = dev;
118
119 g_list_free(manager->iop_to_set);
120 manager->iop_to_set = NULL;
121 dev->preview_pipe->autoset = TRUE;
122 for(GList *mod = g_list_first(dev->iop); mod; mod = g_list_next(mod))
123 {
124 dt_iop_module_t *module = (dt_iop_module_t *)mod->data;
125 if(module->enabled && !IS_NULL_PTR(module->autoset) && dt_iop_autoset_module_is_enabled(module))
126 manager->iop_to_set = g_list_append(manager->iop_to_set, module);
127 }
128
129 // Start immediately in case we already have the output in cache. If the
130 // cacheline was not found, the request was sent to the pipeline, so retry later.
131 dt_iop_autoset_advance(dev, manager);
132}
133
135{
136 if(IS_NULL_PTR(dev) || IS_NULL_PTR(manager)) return 1;
137
138 if(IS_NULL_PTR(manager->input_wait))
139 manager->input_wait = g_malloc0(sizeof(dt_dev_pixelpipe_cache_wait_t));
141 dt_dev_pixelpipe_t *pipe = dev->preview_pipe;
142
143 dt_iop_module_t *module = _dt_iop_autoset_peek_next(dev, manager);
144 if(IS_NULL_PTR(module))
145 {
146 _dt_iop_autoset_finish(pipe, manager, input_wait, "autoset-finished");
147 return 1;
148 }
149
150 // Enter busy cursor exactly when the first autoset operation starts.
151 if(!manager->progress_cursor_active)
152 {
155 manager->progress_cursor_active = TRUE;
156 }
157
158 // Module pieces (pipeline nodes) are not stable in time: the pipeline can be
159 // destroyed and reconstructed, so grab the piece currently attached to the
160 // module rather than caching a reference.
161 const dt_dev_pixelpipe_iop_t *const piece = dt_dev_pixelpipe_get_module_piece(pipe, module);
162 if(IS_NULL_PTR(piece)) return 1;
163 const dt_dev_pixelpipe_iop_t *const input_piece = dt_dev_pixelpipe_get_prev_enabled_piece(pipe, piece);
164 if(IS_NULL_PTR(input_piece)) return 1;
165
166 // Get the corresponding pipeline cache entry immediately if possible, else the
167 // following function requests a partial pipe recompute and we retry later.
168 dt_pixel_cache_entry_t *entry = NULL;
169 void *input = NULL;
170 dt_dev_pixelpipe_cache_wait_set_owner(input_wait, "autoset-input", manager);
171 if(!dt_dev_pixelpipe_cache_peek_gui(pipe, input_piece, &input, &entry,
172 input_wait, _dt_iop_autoset_restart_cache_wait, manager))
173 return 1;
174
175 // module->autoset manipulates the module's internal parameters outside of the
176 // normal (GUI) control flow. Protect concurrent params writes from the GUI and
177 // write history while we still hold the lock.
178 //
179 // Pin the cacheline (refcount) *before* read-locking it, exactly like the color
180 // picker / colorequal / histogram consumers do: peek_gui() hands back an unreffed
181 // entry (its internal read lock is already released), so without a ref the worker
182 // could evict this intermediate module-input cacheline — which has refcount 0
183 // between renders — during the autoset() sampling call, freeing the buffer under us.
187 module->autoset(module, pipe, piece, input);
190 dt_dev_add_history_item(dev, module, FALSE, FALSE);
192
193 // Params have changed: refresh the module GUI to reflect it.
194 dt_iop_gui_update(module);
195
196 manager->iop_to_set = g_list_remove(manager->iop_to_set, module);
197 if(IS_NULL_PTR(manager->iop_to_set))
198 _dt_iop_autoset_finish(pipe, manager, input_wait, "autoset-list-empty");
199
200 return 0;
201}
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
char * key
int dt_conf_key_exists(const char *key)
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
void dt_control_log_busy_leave()
Definition control.c:856
void dt_control_change_cursor_by_name_and_flush(const char *curs_str)
Apply a named cursor immediatelly and flush display updates for immediate feedback.
Definition control.c:326
void dt_control_log_busy_enter()
Definition control.c:840
darktable_t darktable
Definition darktable.c:183
#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
#define dt_dev_add_history_item(dev, module, enable, redraw)
const dt_dev_pixelpipe_iop_t * dt_dev_pixelpipe_get_module_piece(const dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *module)
void dt_dev_pixelpipe_cache_wait_cleanup(dt_dev_pixelpipe_cache_wait_t *wait, const char *reason)
Cancel one pending GUI cache wait request and clear its runtime state.
const dt_dev_pixelpipe_iop_t * dt_dev_pixelpipe_get_prev_enabled_piece(const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece)
void dt_dev_pixelpipe_cache_wait_set_owner(dt_dev_pixelpipe_cache_wait_t *wait, const char *owner_tag, gpointer owner_object)
Attach debug ownership metadata to one cache wait request.
gboolean dt_dev_pixelpipe_cache_peek_gui(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, void **data, dt_pixel_cache_entry_t **cache_entry, dt_dev_pixelpipe_cache_wait_t *wait, dt_dev_pixelpipe_cache_ready_callback_t restart, gpointer restart_data)
void dt_iop_gui_update(dt_iop_module_t *module)
Definition imageop.c:2133
static void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module) ACQUIRE(&module -> gui_lock)
Definition imageop.h:450
static void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module) RELEASE(&module -> gui_lock)
Definition imageop.h:456
int dt_iop_autoset_advance(struct dt_develop_t *dev, dt_autoset_manager_t *manager)
gboolean dt_iop_autoset_module_is_enabled(const dt_iop_module_t *module)
Definition iop-autoset.c:88
void dt_iop_autoset_build_list(struct dt_develop_t *dev, dt_autoset_manager_t *manager)
static void _dt_iop_autoset_progress_leave(dt_autoset_manager_t *manager)
Definition iop-autoset.c:39
static void _dt_iop_autoset_finish(dt_dev_pixelpipe_t *pipe, dt_autoset_manager_t *manager, dt_dev_pixelpipe_cache_wait_t *input_wait, const char *reason)
Definition iop-autoset.c:51
static void _dt_iop_autoset_restart_cache_wait(gpointer user_data)
Definition iop-autoset.c:30
void dt_iop_autoset_module_set_enabled(const dt_iop_module_t *module, const gboolean enabled)
Definition iop-autoset.c:98
gchar * dt_iop_autoset_get_conf_key(const dt_iop_module_t *module)
Definition iop-autoset.c:81
static dt_iop_module_t * _dt_iop_autoset_peek_next(struct dt_develop_t *dev, dt_autoset_manager_t *manager)
Definition iop-autoset.c:65
void dt_dev_pixelpipe_cache_ref_count_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Increase/Decrease the reference count on the cache line as to prevent LRU item removal....
void dt_dev_pixelpipe_cache_rdlock_entry(dt_dev_pixelpipe_cache_t *cache, gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
Pixelpipe cache for storing intermediate results in the pixelpipe.
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
struct dt_develop_t * dev
Definition iop-autoset.h:25
gboolean progress_cursor_active
Definition iop-autoset.h:24
GList * iop
Definition develop.h:285
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:247
GModule *dt_dev_operation_t op
Definition imageop.h:286