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 "system/macros.h"
21#include "develop/develop.h"
22#include "develop/pixelpipe.h"
25#include "develop/imageop.h"
26#include "common/conf.h"
27#include "control/control.h"
28
29#include <glib.h>
30
31static void _dt_iop_autoset_restart_cache_wait(gpointer user_data)
32{
33 dt_autoset_manager_t *manager = (dt_autoset_manager_t *)user_data;
34 if(IS_NULL_PTR(manager) || IS_NULL_PTR(manager->dev)) return;
35
36 dt_iop_autoset_advance(manager->dev, manager);
37}
38
39// Leave the busy cursor/progress state, exactly once.
41{
42 if(!IS_NULL_PTR(manager) && manager->progress_cursor_active)
43 {
46 }
47}
48
49// Tear down an autoset run: drop any pending cache-wait, clear the pipe flag
50// and release the busy cursor. Called whenever the queue can no longer be
51// processed (exhausted, or every remaining module went stale).
53 dt_dev_pixelpipe_cache_wait_t *input_wait, const char *reason)
54{
55 if(!IS_NULL_PTR(input_wait))
56 dt_dev_pixelpipe_cache_wait_cleanup(input_wait, reason);
57 if(!IS_NULL_PTR(pipe))
58 pipe->autoset = FALSE;
60}
61
62// Pop the next still-valid module off the queue, discarding stale entries.
63// The pipeline can be torn down and rebuilt between two advance() calls, so a
64// queued module pointer may dangle, get reused for a different module, or lose
65// its autoset callback. Re-validate against the live module list before use.
67{
68 GList *mod = g_list_first(manager->iop_to_set);
69 while(mod)
70 {
71 dt_iop_module_t *module = (dt_iop_module_t *)mod->data;
72 if(!IS_NULL_PTR(module) && g_list_find(dev->iop, module) && !IS_NULL_PTR(module->autoset))
73 return module;
74
75 // Stale entry: drop it and look at the next one.
76 manager->iop_to_set = g_list_delete_link(manager->iop_to_set, mod);
77 mod = g_list_first(manager->iop_to_set);
78 }
79 return NULL;
80}
81
83{
84 if(IS_NULL_PTR(module)) return NULL;
85 gchar *key = g_strdup_printf("plugins/darkroom/autoset/%s/%i", module->op, module->multi_priority);
86 return key;
87}
88
90{
91 gchar *key = dt_iop_autoset_get_conf_key(module);
92 if(IS_NULL_PTR(key)) return FALSE;
93
94 const gboolean enabled = !dt_conf_key_exists(key) || dt_conf_get_int(key) != 0;
95 g_free(key);
96 return enabled;
97}
98
100{
101 gchar *key = dt_iop_autoset_get_conf_key(module);
102 if(IS_NULL_PTR(key)) return;
103
104 dt_conf_set_int(key, enabled ? 1 : 0);
105 g_free(key);
106}
107
109{
110 if(IS_NULL_PTR(dev) || IS_NULL_PTR(manager)) return;
111
112 if(IS_NULL_PTR(manager->input_wait))
113 manager->input_wait = g_malloc0(sizeof(dt_dev_pixelpipe_cache_wait_t));
115 "autoset-build-list-reset");
116
117 manager->dev = dev;
119
120 g_list_free(manager->iop_to_set);
121 manager->iop_to_set = NULL;
122 dev->preview_pipe->autoset = TRUE;
123 for(GList *mod = g_list_first(dev->iop); mod; mod = g_list_next(mod))
124 {
125 dt_iop_module_t *module = (dt_iop_module_t *)mod->data;
126 if(module->enabled && !IS_NULL_PTR(module->autoset) && dt_iop_autoset_module_is_enabled(module))
127 manager->iop_to_set = g_list_append(manager->iop_to_set, module);
128 }
129
130 // Start immediately in case we already have the output in cache. If the
131 // cacheline was not found, the request was sent to the pipeline, so retry later.
132 dt_iop_autoset_advance(dev, manager);
133}
134
136{
137 if(IS_NULL_PTR(dev) || IS_NULL_PTR(manager)) return 1;
138
139 if(IS_NULL_PTR(manager->input_wait))
140 manager->input_wait = g_malloc0(sizeof(dt_dev_pixelpipe_cache_wait_t));
142 dt_dev_pixelpipe_t *pipe = dev->preview_pipe;
143
144 dt_iop_module_t *module = _dt_iop_autoset_peek_next(dev, manager);
145 if(IS_NULL_PTR(module))
146 {
147 _dt_iop_autoset_finish(pipe, manager, input_wait, "autoset-finished");
148 return 1;
149 }
150
151 // Enter busy cursor exactly when the first autoset operation starts.
152 if(!manager->progress_cursor_active)
153 {
156 manager->progress_cursor_active = TRUE;
157 }
158
159 // Module pieces (pipeline nodes) are not stable in time: the pipeline can be
160 // destroyed and reconstructed, so grab the piece currently attached to the
161 // module rather than caching a reference.
162 const dt_dev_pixelpipe_iop_t *const piece = dt_dev_pixelpipe_get_module_piece(pipe, module);
163 if(IS_NULL_PTR(piece)) return 1;
164 const dt_dev_pixelpipe_iop_t *const input_piece = dt_dev_pixelpipe_get_prev_enabled_piece(pipe, piece);
165 if(IS_NULL_PTR(input_piece)) return 1;
166
167 // Get the corresponding pipeline cache entry immediately if possible, else the
168 // following function requests a partial pipe recompute and we retry later.
169 dt_pixel_cache_entry_t *entry = NULL;
170 void *input = NULL;
171 dt_dev_pixelpipe_cache_wait_set_owner(input_wait, "autoset-input", manager);
172 /* Retained: `peek_gui_retained()` takes the reference under the same hold of the cache lock as
173 * the lookup, so the worker cannot evict this intermediate module-input cacheline -- which has
174 * refcount 0 between renders -- in between and free the buffer under the autoset() call below. */
175 if(!dt_dev_pixelpipe_cache_peek_gui_retained(pipe, input_piece, &input, &entry,
176 input_wait, _dt_iop_autoset_restart_cache_wait, manager))
177 return 1;
178
179 // module->autoset manipulates the module's internal parameters outside of the
180 // normal (GUI) control flow. Protect concurrent params writes from the GUI and
181 // write history while we still hold the lock.
184 module->autoset(module, pipe, piece, input);
187 dt_dev_add_history_item(dev, module, FALSE, FALSE);
189
190 // Params have changed: refresh the module GUI to reflect it.
191 dt_iop_gui_update(module);
192
193 manager->iop_to_set = g_list_remove(manager->iop_to_set, module);
194 if(IS_NULL_PTR(manager->iop_to_set))
195 _dt_iop_autoset_finish(pipe, manager, input_wait, "autoset-list-empty");
196
197 return 0;
198}
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
int dt_conf_key_exists(const char *key)
Does key have a value?
void dt_conf_set_int(const char *name, int val)
int dt_conf_get_int(const char *name)
Integer for name, clamped to the bounds declared in the XML.
void dt_control_log_busy_leave()
Definition control.c:903
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:335
void dt_control_log_busy_enter()
Definition control.c:887
#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_retained(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)
gboolean enabled
–doc was passed on the command line
void dt_iop_gui_update(dt_iop_module_t *module)
void dt_iop_gui_leave_critical_section(dt_iop_module_t *const module)
Release what dt_iop_gui_enter_critical_section() took. Also a no-op headless.
void dt_iop_gui_enter_critical_section(dt_iop_module_t *const module)
Take the module's GUI lock, serialising access to its dt_iop_gui_data_t.
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:89
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:40
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:52
static void _dt_iop_autoset_restart_cache_wait(gpointer user_data)
Definition iop-autoset.c:31
void dt_iop_autoset_module_set_enabled(const dt_iop_module_t *module, const gboolean enabled)
Definition iop-autoset.c:99
gchar * dt_iop_autoset_get_conf_key(const dt_iop_module_t *module)
Definition iop-autoset.c:82
static dt_iop_module_t * _dt_iop_autoset_peek_next(struct dt_develop_t *dev, dt_autoset_manager_t *manager)
Definition iop-autoset.c:66
#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
char * key
void dt_dev_pixelpipe_cache_ref_count_entry(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(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_develop_t * dev
Definition iop-autoset.h:28
gboolean progress_cursor_active
Definition iop-autoset.h:27
GList * iop
Definition develop.h:269
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:214
dt_dev_operation_t op
Definition imageop.h:259
One consumer's outstanding request, owned by that consumer, not by the queue.