Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
pixelpipe_raster_masks.c
Go to the documentation of this file.
1
15// This file is textually #included into pixelpipe_hb.c (see the doc block above), so
16// these guarded includes fold into that TU; they are named here because THIS file uses them.
17#include "common/glib_utils.h" // dt_string_replace
18#include "control/user_message.h" // dt_control_alert
19
20#include <glib/gi18n.h> // _(), to translate the messages
21
34 dt_dev_pixelpipe_iop_t *source_piece,
35 dt_dev_pixelpipe_iop_t *current_piece,
36 const dt_iop_module_t *target_module)
37{
38 gboolean success = TRUE;
39 gchar *clean_target_name = !IS_NULL_PTR(target_module)
40 ? dt_string_replace(target_module->name(), "_")
41 : g_strdup(_("export"));
42 gchar *target_name = !IS_NULL_PTR(target_module)
43 ? g_strdup_printf("%s (%s)", clean_target_name, target_module->multi_name)
44 : g_strdup(clean_target_name);
45
46 if(IS_NULL_PTR(source_piece)
47 || (!IS_NULL_PTR(target_module) && IS_NULL_PTR(current_piece)))
48 {
49 dt_print(DT_DEBUG_MASKS,"[raster masks] ERROR: source: %s, current: %s\n",
50 (!IS_NULL_PTR(source_piece)) ? "is defined" : "is undefined",
51 (!IS_NULL_PTR(current_piece)) ? "is defined" : "is undefined");
52
53 // The message says what to check, the item which modules and which image: one window per cause.
54 if(IS_NULL_PTR(source_piece))
55 {
56 gchar *item = g_strdup_printf(_("`%s` on %s"), target_name, pipe->dev->image_storage.fullpath);
57 dt_control_alert(_("Module failed"),
58 _("A module is trying to reuse a mask from a module but it can't be found.\n"
59 "\n- Check if the module providing its masks has not been deleted."),
60 item);
61 dt_free(item);
62 }
63 else
64 {
65 gchar *clean_source_name = dt_string_replace(source_piece->module->name(), "_");
66 gchar *source_name = g_strdup_printf("%s (%s)", clean_source_name, source_piece->module->multi_name);
67 gchar *item = g_strdup_printf(_("`%s`, mask from `%s`, on %s"), target_name, source_name,
69 dt_control_alert(_("Module failed"),
70 _("A module is trying to reuse a mask from a module but it can't be found.\n"
71 "\n- Check if the module providing its masks has not been moved above it."),
72 item);
73 dt_free(item);
74 dt_free(source_name);
75 dt_free(clean_source_name);
76 }
77
78 dt_print(DT_DEBUG_MASKS, "[raster masks] no source module for module %s could be found\n", target_name);
79 success = FALSE;
80 }
81
82 if(success && !source_piece->enabled)
83 {
84 gchar *clean_source_name = dt_string_replace(source_piece->module->name(), "_");
85 gchar *source_name = g_strdup_printf("%s (%s)", clean_source_name, source_piece->module->multi_name);
86 gchar *item = g_strdup_printf(_("`%s`, mask from `%s`, on %s"), target_name, source_name,
88 dt_control_alert(_("Module failed"),
89 _("A module is trying to reuse a mask from a disabled module.\n"
90 "Disabled modules cannot provide their masks to other modules.\n"
91 "\n- Please enable the module providing the mask or change the raster mask in the "
92 "module reusing it."),
93 item);
94 dt_free(item);
95
96 dt_print(DT_DEBUG_MASKS, "[raster masks] module %s trying to reuse a mask from disabled instance of %s\n",
97 target_name, source_name);
98
99 dt_free(clean_source_name);
100 dt_free(source_name);
101 success = FALSE;
102 }
103
104 dt_free(clean_target_name);
105 dt_free(target_name);
106 return success;
107}
108
110 const int raster_mask_id, const dt_iop_module_t *target_module,
111 int *error)
112{
113 if(!IS_NULL_PTR(error)) *error = 0;
114
115 gchar *clean_target_name = !IS_NULL_PTR(target_module)
116 ? dt_string_replace(target_module->name(), "_")
117 : g_strdup(_("export"));
118 gchar *target_name = !IS_NULL_PTR(target_module)
119 ? g_strdup_printf("%s (%s)", clean_target_name, target_module->multi_name)
120 : g_strdup(clean_target_name);
121
122 if(IS_NULL_PTR(raster_mask_source))
123 {
124 dt_print(DT_DEBUG_MASKS, "[raster masks] The source module of the mask for %s was not found\n", target_name);
125 dt_free(clean_target_name);
126 dt_free(target_name);
127 return NULL;
128 }
129
130 float *raster_mask = NULL;
131
132 dt_dev_pixelpipe_iop_t *source_piece = NULL;
133 dt_dev_pixelpipe_iop_t *current_piece = NULL;
134 GList *source_iter = NULL;
135 for(source_iter = g_list_last(pipe->nodes); source_iter; source_iter = g_list_previous(source_iter))
136 {
137 dt_dev_pixelpipe_iop_t *candidate = (dt_dev_pixelpipe_iop_t *)source_iter->data;
138 if(candidate->module == target_module)
139 current_piece = candidate;
140 else if(candidate->module == raster_mask_source)
141 {
142 source_piece = candidate;
143 break;
144 }
145 }
146
147 const int err_ret = !_dt_dev_raster_mask_check(pipe, source_piece, current_piece, target_module);
148 if(!IS_NULL_PTR(error)) *error = err_ret;
149
150 if(!err_ret)
151 {
152 const uint64_t provider_hash = source_piece->global_hash;
153 const uint64_t raster_hash
154 = dt_dev_pixelpipe_raster_mask_hash(source_piece, raster_mask_id);
155
156 gchar *clean_source_name = dt_string_replace(source_piece->module->name(), "_");
157 gchar *source_name = g_strdup_printf("%s (%s)", clean_source_name, source_piece->module->multi_name);
158 dt_pixel_cache_entry_t *raster_entry = NULL;
159 void *cache_data = NULL;
160 const gboolean found = dt_dev_pixelpipe_cache_ref_entry_by_hash(
161 raster_hash, &cache_data, &raster_entry);
162
164 if(found && !IS_NULL_PTR(cache_data) && !IS_NULL_PTR(raster_entry))
165 {
166 const size_t mask_size
167 = sizeof(float) * (size_t)source_piece->roi_out.width * source_piece->roi_out.height;
169 (size_t)source_piece->roi_out.width * source_piece->roi_out.height, pipe->type);
170 if(IS_NULL_PTR(raster_mask))
171 {
173 FALSE, raster_entry);
174 if(!IS_NULL_PTR(error)) *error = 1;
175 dt_free(clean_source_name);
176 dt_free(source_name);
177 dt_free(clean_target_name);
178 dt_free(target_name);
179 return NULL;
180 }
181
182 // The cache owns the canonical mask. Copy it under a read lock so the
183 // caller can freely distort and release its private working buffer.
185 TRUE, raster_entry);
186 memcpy(raster_mask, cache_data, mask_size);
188 FALSE, raster_entry);
190 FALSE, raster_entry);
191
193 "[raster masks] found cached mask id %i from %s for module %s"
194 " in pipe %s with hash %" PRIu64 "\n",
195 raster_mask_id, source_name, target_name, type, raster_hash);
196 dt_dev_pixelpipe_unset_reentry(pipe, provider_hash);
197 }
198 else
199 {
200 if(!IS_NULL_PTR(raster_entry))
202 FALSE, raster_entry);
203
205 "[raster masks] missing source=%s instance=%d target=%s instance=%d"
206 " requested_id=%d cache_hash=%" PRIu64 " source_enabled=%d pipe=%s\n",
207 source_piece->module->op, source_piece->module->multi_priority,
208 !IS_NULL_PTR(target_module) ? target_module->op : "export",
209 !IS_NULL_PTR(target_module) ? target_module->multi_priority : -1,
210 raster_mask_id, raster_hash, source_piece->enabled,
211 type);
212
214 "[raster masks] mask id %i from %s for module %s could not be found"
215 " in the global cache for pipe %s.\n",
216 raster_mask_id, source_name, target_name, type);
217
218 // A cache miss can still happen after LRU eviction. Cached provider
219 // pixels cannot reconstruct the side-band mask, so interactive pipes get
220 // one targeted provider retry; export callers pass no error pointer and
221 // simply report the missing mask.
222 if(!IS_NULL_PTR(error))
223 {
224 if(dt_dev_pixelpipe_set_reentry(pipe, provider_hash))
226 *error = 1;
227 }
228
229 dt_free(clean_source_name);
230 dt_free(source_name);
231 dt_free(clean_target_name);
232 dt_free(target_name);
233 return NULL;
234 }
235
236 for(GList *iter = g_list_next(source_iter); iter; iter = g_list_next(iter))
237 {
238 dt_dev_pixelpipe_iop_t *module = (dt_dev_pixelpipe_iop_t *)iter->data;
239
240 if(module->enabled
241 && !dt_dev_pixelpipe_activemodule_disables_currentmodule(module->module->dev, module->module))
242 {
243 if(module->module->distort_mask
244 && !(!strcmp(module->module->op, "finalscale")
245 && module->roi_in.width == 0
246 && module->roi_in.height == 0))
247 {
248 float *transformed_mask = dt_pixelpipe_cache_alloc_align_float_cache(
249 (size_t)module->roi_out.width * module->roi_out.height, 0);
250 if(IS_NULL_PTR(transformed_mask))
251 {
252 dt_print(DT_DEBUG_MASKS, "[raster masks] could not allocate memory for transformed mask\n");
253 if(!IS_NULL_PTR(error)) *error = 1;
255 dt_free(clean_source_name);
256 dt_free(source_name);
257 dt_free(clean_target_name);
258 dt_free(target_name);
259 return NULL;
260 }
261
262 module->module->distort_mask(module->module, pipe, module, raster_mask, transformed_mask,
263 &module->roi_in, &module->roi_out);
265 raster_mask = transformed_mask;
266 dt_print(DT_DEBUG_MASKS, "[raster masks] doing transform\n");
267 }
268 else if(!module->module->distort_mask
269 && (module->roi_in.width != module->roi_out.width
270 || module->roi_in.height != module->roi_out.height
271 || module->roi_in.x != module->roi_out.x
272 || module->roi_in.y != module->roi_out.y))
273 dt_print(DT_DEBUG_MASKS, "FIXME: module `%s' changed the roi from %d x %d @ %d / %d to %d x %d | %d / %d but doesn't have "
274 "distort_mask() implemented!\n", module->module->op, module->roi_in.width,
275 module->roi_in.height, module->roi_in.x, module->roi_in.y,
276 module->roi_out.width, module->roi_out.height, module->roi_out.x,
277 module->roi_out.y);
278 }
279
280 if(module->module == target_module)
281 {
282 gchar *clean_module_name = dt_string_replace(module->module->name(), "_");
283 dt_print(DT_DEBUG_MASKS, "[raster masks] found mask id %i from %s for module %s (%s) in pipe %s\n",
284 raster_mask_id, source_name, clean_module_name,
285 module->module->multi_name, dt_pixelpipe_get_pipe_name(pipe->type));
286 dt_free(clean_module_name);
287 break;
288 }
289 }
290
291 dt_free(clean_source_name);
292 dt_free(source_name);
293 }
294
295 dt_free(clean_target_name);
296 dt_free(target_name);
297 return raster_mask;
298}
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_control_alert(const char *title, const char *message, const char *item)
Tell the user something that must not go unseen: what it says stays true after a toast would have fad...
Definition control.c:883
gboolean dt_dev_pixelpipe_activemodule_disables_currentmodule(struct dt_develop_t *dev, struct dt_iop_module_t *current_module)
static gchar * dt_string_replace(const char *string, const char *to_replace)
Definition glib_utils.h:64
static const dt_dev_pixelpipe_t * pipe
Definition layers.h:49
_lib_location_type_t type
Definition location.c:1
@ DT_DEBUG_DEV
Definition logging.h:53
@ DT_DEBUG_MASKS
Definition logging.h:62
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#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(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
Definition mem_alloc.h:171
uint64_t dt_dev_pixelpipe_raster_mask_hash(const dt_dev_pixelpipe_iop_t *piece, const int raster_mask_id)
Definition pixelpipe.c:53
void dt_dev_pixelpipe_cache_ref_count_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Take or release one reference on a cache line. A referenced line is never evicted,...
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.
gboolean dt_dev_pixelpipe_cache_ref_entry_by_hash(const uint64_t hash, void **data, dt_pixel_cache_entry_t **entry)
Resolve and retain an existing cache entry by hash.
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
char * dt_pixelpipe_get_pipe_name(dt_dev_pixelpipe_type_t pipe_type)
gboolean dt_dev_pixelpipe_unset_reentry(dt_dev_pixelpipe_t *pipe, uint64_t hash)
Remove the re-entry pipeline flag, only if the object identifier is the one that set it....
gboolean dt_dev_pixelpipe_set_reentry(dt_dev_pixelpipe_t *pipe, uint64_t hash)
Set the re-entry pipeline flag, only if no object is already capturing it.
static gboolean _dt_dev_raster_mask_check(const dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *source_piece, dt_dev_pixelpipe_iop_t *current_piece, const dt_iop_module_t *target_module)
Check that the raster-mask provider/consumer relation is still valid in the current pipe.
float * dt_dev_get_raster_mask(dt_dev_pixelpipe_t *pipe, const dt_iop_module_t *raster_mask_source, const int raster_mask_id, const dt_iop_module_t *target_module, int *error)
unsigned __int64 uint64_t
Definition strptime.c:75
struct dt_iop_module_t *void * data
dt_dev_pixelpipe_type_t type
struct dt_develop_t * dev
dt_image_t image_storage
Definition develop.h:225
char fullpath[DT_PATH_MAX]
Definition image.h:396
char multi_name[128]
Definition imageop.h:387
dt_dev_operation_t op
Definition imageop.h:259
int width
Definition format.h:50
int height
Definition format.h:50
Telling the user something happened.