Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
layers.c
Go to the documentation of this file.
2
3#include "iop/drawlayer/cache.h" // dt_drawlayer_cache_patch_*()
4#include "iop/drawlayer/io.h" // dt_drawlayer_io_*()
5#include "iop/drawlayer/runtime.h" // dt_iop_drawlayer_gui_data_t (dereferenced here)
6#include "iop/drawlayer/worker.h" // dt_drawlayer_worker_*()
7
8#include "control/user_message.h" // dt_control_log()
9#include "develop/develop.h" // dt_dev_geometry_snapshot(), dt_dev_viewport_*()
10#include "develop/dev_history.h" // dt_dev_transient_params_clear()
11#include "develop/imageop_gui.h" // dt_iop_gui_data()
12#include "develop/pixelpipe_hb.h" // dt_dev_pixelpipe_resync_history_main()
13#include "widgets/bauhaus.h" // dt_bauhaus_combobox_*()
14#include "widgets/widget_settings.h" // dt_gui_widget_freeze()
15
34
35void dt_drawlayer_layers_append_error(GString *errors, const char *message)
36{
37 if(IS_NULL_PTR(errors) || IS_NULL_PTR(message) || message[0] == '\0') return;
38 if(errors->len > 0) g_string_append(errors, "; ");
39 g_string_append(errors, message);
40}
41
42void dt_drawlayer_layers_log_errors(GString *errors)
43{
44 if(IS_NULL_PTR(errors)) return;
45 if(errors->len > 0) dt_control_log("%s", errors->str);
46}
47
49{
52 if(IS_NULL_PTR(g)) return;
53 // Scope guard: the freeze spans the rest of the function, which has an early return; the
54 // guard releases it on every exit path (no manual end-before-return needed).
56
57 while(dt_bauhaus_combobox_length(g->controls.layer_select) > 0)
58 dt_bauhaus_combobox_remove_at(g->controls.layer_select, dt_bauhaus_combobox_length(g->controls.layer_select) - 1);
59
60 if(IS_NULL_PTR(self->dev))
61 {
62 dt_bauhaus_combobox_set(g->controls.layer_select, -1);
63 return;
64 }
65
66 char path[DT_PATH_MAX] = { 0 };
67 char **names = NULL;
68 int count = 0;
69 if(dt_drawlayer_io_sidecar_path(self->dev->image_storage.id, path, sizeof(path)))
71
72 int active = -1;
73 const int listed_count = count;
74 for(int i = 0; i < count; i++)
75 {
76 const char *page_name = names[i] ? names[i] : "";
77 dt_bauhaus_combobox_add(g->controls.layer_select, page_name);
78 if(params->layer_order == i || (params->layer_name[0] && !g_strcmp0(page_name, params->layer_name)))
79 active = i;
80 }
81
83 if(active >= 0)
84 dt_bauhaus_combobox_set(g->controls.layer_select, active);
85 else if(listed_count > 0 && !dt_drawlayer_layer_name_non_empty(params->layer_name))
86 dt_bauhaus_combobox_set(g->controls.layer_select, 0);
87 else
88 /* The combobox is reserved for layers that already exist in the TIFF
89 * sidecar. Keep unsaved or missing module attachments out of the shared
90 * list so switching layers never invents phantom entries. */
91 dt_bauhaus_combobox_set(g->controls.layer_select, -1);
92}
93
95{
96 if(IS_NULL_PTR(g)) return;
97 g->stroke.stroke_sample_count = 0;
98 g->stroke.stroke_event_index = 0;
99 g->stroke.last_dab_valid = FALSE;
103}
104
106{
107 /* Cache identity belongs to the module orchestration layer because it
108 * combines sidecar identity with GUI/module state (active image, selected
109 * layer, in-memory patch ownership). The low-level TIFF primitives stay in
110 * drawlayer/io.c. */
111 if(IS_NULL_PTR(g) || IS_NULL_PTR(key) || !g->process.cache_valid || IS_NULL_PTR(g->process.base_patch.pixels)) return FALSE;
112 if(g->process.cache_imgid != key->imgid || g->process.base_patch.width != key->layer_width
113 || g->process.base_patch.height != key->layer_height)
114 return FALSE;
115
116 /* Once a layer is cached in memory, `process()` should treat that payload as
117 * authoritative until we explicitly reload or flush it. The page index in the
118 * params is only a sidecar lookup hint and may legitimately drift after sidecar
119 * rewrites or page reordering. Layer names are unique and stable by design, so
120 * prefer them for cache identity. Falling back to the page index here causes
121 * `process()` to re-open the TIFF and re-scan directories even though the
122 * correct pixels are already in memory. */
123 const char *target_name = key->layer_name ? key->layer_name : "";
124 if(target_name[0] != '\0' || g->process.cache_layer_name[0] != '\0') return !g_strcmp0(g->process.cache_layer_name, target_name);
125
126 if(key->layer_order >= 0 && g->process.cache_layer_order >= 0)
127 return g->process.cache_layer_order == key->layer_order;
128 return TRUE;
129}
130
132{
133 /* Make sure `base_patch` mirrors the currently selected sidecar layer.
134 * The low-level TIFF read/write primitives live in drawlayer/io.c, while this
135 * function stays here because it orchestrates cache lifetime, widget state,
136 * prompting, and history/UI side effects around those I/O operations. */
139 if(IS_NULL_PTR(g) || IS_NULL_PTR(self->dev)) return FALSE;
140
142 int layer_width = 0;
143 int layer_height = 0;
144 const int32_t imgid = self->dev->image_storage.id;
145 GMainContext *const ui_ctx = g_main_context_default();
146 const gboolean ui_thread = ui_ctx && g_main_context_is_owner(ui_ctx);
147 if(!dt_drawlayer_resolve_layer_geometry(self, NULL, NULL, &layer_width, &layer_height, NULL, NULL))
148 {
150 layer_width = geometry.raw_width;
151 layer_height = geometry.raw_height;
152 }
153 if(imgid <= 0 || layer_width <= 0 || layer_height <= 0) return FALSE;
155 {
157 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
158 g->process.cache_valid = FALSE;
159 g->process.cache_dirty = FALSE;
160 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
161 g->process.cache_imgid = -1;
162 g->process.cache_layer_name[0] = '\0';
163 g->process.cache_layer_order = -1;
165 if(ui_thread) dt_drawlayer_refresh_layer_widgets(self);
166 return TRUE;
167 }
168 const drawlayer_layer_cache_key_t cache_key = {
169 .imgid = imgid,
170 .layer_width = layer_width,
171 .layer_height = layer_height,
172 .layer_name = params->layer_name,
173 .layer_order = params->layer_order,
174 };
175
176 GString *errors = g_string_new(NULL);
177
178 char current_profile[DRAWLAYER_PROFILE_SIZE] = { 0 };
179 const gboolean have_current_profile = dt_drawlayer_current_work_profile_key(self, self->dev->iop, self->dev->pipe,
180 current_profile, sizeof(current_profile));
181 if(!have_current_profile)
182 dt_drawlayer_layers_append_error(errors, _("failed to resolve drawlayer working profile"));
183 else if(params->work_profile[0] == '\0')
184 g_strlcpy(params->work_profile, current_profile, sizeof(params->work_profile));
185 else if(g_strcmp0(params->work_profile, current_profile))
186 dt_drawlayer_layers_append_error(errors, _("drawlayer working profile mismatch"));
187
188 if(_layer_cache_matches(g, &cache_key))
189 {
191 g_string_free(errors, TRUE);
192 return TRUE;
193 }
194
196 {
197 dt_drawlayer_layers_append_error(errors, _("failed to write drawing layer sidecar"));
199 g_string_free(errors, TRUE);
200 return FALSE;
201 }
202 /* We are about to replace/rebind `g->process.base_patch`; drop all explicit extra
203 * refs from the previous entry first so counters never leak across entries. */
205
206 int created = 0;
207 if(!dt_drawlayer_cache_patch_alloc_shared(&g->process.base_patch,
208 dt_drawlayer_params_cache_hash(imgid, params, layer_width, layer_height),
210 "drawlayer sidecar cache", &created))
211 {
213 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
214 g->process.cache_valid = FALSE;
216 g_string_free(errors, TRUE);
217 return FALSE;
218 }
220 "drawlayer stroke mask"))
221 {
223 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
224 g->process.cache_valid = FALSE;
225 dt_drawlayer_layers_append_error(errors, _("failed to allocate drawlayer stroke mask"));
227 g_string_free(errors, TRUE);
228 return FALSE;
229 }
230 if(created)
231 {
232 dt_drawlayer_cache_patch_wrlock(&g->process.base_patch);
233 dt_drawlayer_cache_clear_transparent_float(g->process.base_patch.pixels, (size_t)layer_width * layer_height);
234 dt_drawlayer_cache_patch_wrunlock(&g->process.base_patch);
235 }
236
237 gboolean ok = TRUE;
238 gboolean cache_loaded = FALSE;
239 gboolean file_exists = FALSE;
240 char path[DT_PATH_MAX] = { 0 };
241
242 if(!created)
243 {
244 cache_loaded = TRUE;
245 }
246 else if(!dt_drawlayer_io_sidecar_path(imgid, path, sizeof(path)))
247 {
249 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
250 g->process.cache_valid = FALSE;
251 dt_drawlayer_layers_append_error(errors, _("failed to resolve drawlayer sidecar path"));
253 g_string_free(errors, TRUE);
254 return TRUE;
255 }
256
257 if(created) file_exists = g_file_test(path, G_FILE_TEST_EXISTS);
258
259 if(created && !file_exists)
260 {
261 cache_loaded = TRUE;
262 params->layer_order = -1;
264 }
265 else if(created)
266 {
267 const gboolean pending_new_layer = (params->layer_order < 0 && params->sidecar_timestamp == 0);
268 drawlayer_dir_info_t info = { 0 };
269 dt_drawlayer_io_layer_info_t io_info = { 0 };
270 if(!dt_drawlayer_io_find_layer(path, params->layer_name, -1, &io_info))
271 {
272 if(pending_new_layer)
273 {
274 cache_loaded = TRUE;
275 }
276 else
277 {
278 g_snprintf(g->session.missing_layer_error, sizeof(g->session.missing_layer_error),
279 _("The drawing layer \"%s\" was not found in the sidecar TIFF."),
281 params->layer_name[0] = '\0';
282 params->layer_order = -1;
284 memset(params->work_profile, 0, sizeof(params->work_profile));
286 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
287 g->process.cache_valid = FALSE;
288 g->process.cache_dirty = FALSE;
289 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
290 g->process.cache_imgid = -1;
291 g->process.cache_layer_name[0] = '\0';
292 g->process.cache_layer_order = -1;
295 }
296 }
297 else
298 {
299 info.found = io_info.found;
300 info.index = io_info.index;
301 info.count = io_info.count;
302 info.width = io_info.width;
303 info.height = io_info.height;
304 g_strlcpy(info.name, io_info.name, sizeof(info.name));
305 g_strlcpy(info.work_profile, io_info.work_profile, sizeof(info.work_profile));
306 if(g) g->session.missing_layer_error[0] = '\0';
307 params->layer_order = info.index;
308 if(info.work_profile[0] != '\0' && params->work_profile[0] == '\0')
309 g_strlcpy(params->work_profile, info.work_profile, sizeof(params->work_profile));
310
311 if(have_current_profile && info.work_profile[0] != '\0' && g_strcmp0(info.work_profile, current_profile))
312 dt_drawlayer_layers_append_error(errors, _("drawlayer sidecar profile mismatch"));
313
314 dt_drawlayer_cache_patch_wrlock(&g->process.base_patch);
315 dt_drawlayer_io_patch_t io_patch = {
316 .x = g->process.base_patch.x,
317 .y = g->process.base_patch.y,
318 .width = g->process.base_patch.width,
319 .height = g->process.base_patch.height,
320 .pixels = g->process.base_patch.pixels,
321 };
322 const gboolean loaded
324 dt_drawlayer_cache_patch_wrunlock(&g->process.base_patch);
325 if(!loaded)
326 {
327 dt_drawlayer_layers_append_error(errors, _("failed to read drawing layer sidecar"));
328 ok = FALSE;
329 }
330 else
331 {
333 cache_loaded = TRUE;
334 }
335 }
336 }
337
338 if(cache_loaded)
339 {
340 g->process.cache_valid = TRUE;
341 g->process.cache_dirty = FALSE;
342 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
343 g->process.cache_imgid = imgid;
344 g_strlcpy(g->process.cache_layer_name, params->layer_name, sizeof(g->process.cache_layer_name));
345 g->process.cache_layer_order = params->layer_order;
346 if(ui_thread && g->controls.layer_select) dt_drawlayer_layers_populate_list(self);
348 }
350 {
352 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
353 g->process.cache_valid = FALSE;
354 g->process.cache_dirty = FALSE;
355 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
356 }
357
358 if(ui_thread && !cache_loaded) dt_drawlayer_refresh_layer_widgets(self);
360 g_string_free(errors, TRUE);
361 return ok || !cache_loaded;
362}
363
365{
368 if(IS_NULL_PTR(g) || IS_NULL_PTR(self->dev) || !g->process.cache_valid || !g->process.cache_dirty || IS_NULL_PTR(g->process.base_patch.pixels)) return TRUE;
370 if(!dt_drawlayer_layer_name_non_empty(g->process.cache_layer_name)) return FALSE;
371 if(dt_drawlayer_worker_any_active(g->stroke.worker)) dt_drawlayer_worker_wait_idle(self, g->stroke.worker);
372
373 char path[DT_PATH_MAX] = { 0 };
374 const int32_t flush_imgid = (g->process.cache_imgid > 0) ? g->process.cache_imgid : self->dev->image_storage.id;
375 if(flush_imgid <= 0) return TRUE;
376 if(!dt_drawlayer_io_sidecar_path(flush_imgid, path, sizeof(path))) return FALSE;
377
378 int final_order = g->process.cache_layer_order;
379 const char *work_profile = params ? params->work_profile : "";
380 dt_drawlayer_cache_patch_rdlock(&g->process.base_patch);
381 dt_drawlayer_io_patch_t io_patch = {
382 .x = g->process.base_patch.x,
383 .y = g->process.base_patch.y,
384 .width = g->process.base_patch.width,
385 .height = g->process.base_patch.height,
386 .pixels = g->process.base_patch.pixels,
387 };
388 const gboolean ok
389 = dt_drawlayer_io_store_layer(path, g->process.cache_layer_name, g->process.cache_layer_order, work_profile, &io_patch,
390 g->process.base_patch.width, g->process.base_patch.height, FALSE, &final_order);
391 dt_drawlayer_cache_patch_rdunlock(&g->process.base_patch);
392 if(!ok) return FALSE;
393
394 g->process.cache_layer_order = final_order;
395 g->process.cache_dirty = FALSE;
396 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
397
399 if(mutable_params)
400 {
401 if(!g_strcmp0(mutable_params->layer_name, g->process.cache_layer_name)) mutable_params->layer_order = final_order;
403 dt_drawlayer_rekey_shared_base_patch(&g->process.base_patch, flush_imgid, mutable_params);
404 }
406 return TRUE;
407}
408
410{
412 if(IS_NULL_PTR(g) || IS_NULL_PTR(self->dev)) return FALSE;
413
415 if(!dt_drawlayer_compute_view_patch(self, 0.0f, &view)) return FALSE;
416
417 float wx0 = 0.0f, wy0 = 0.0f, wx1 = 0.0f, wy1 = 0.0f;
418 if(!dt_drawlayer_layer_bounds_to_widget_bounds(self, view.layer_x0, view.layer_y0, view.layer_x1,
419 view.layer_y1, &wx0, &wy0, &wx1, &wy1))
420 return FALSE;
421
422 const dt_drawlayer_damaged_rect_t live_view_rect = {
423 .valid = TRUE,
424 .nw = { (int)floorf(view.layer_x0), (int)floorf(view.layer_y0) },
425 .se = { (int)ceilf(view.layer_x1), (int)ceilf(view.layer_y1) },
426 };
427 const dt_drawlayer_damaged_rect_t preview_rect = {
428 .valid = TRUE,
429 .nw = { (int)floorf(wx0), (int)floorf(wy0) },
430 .se = { (int)ceilf(wx1), (int)ceilf(wy1) },
431 };
432
433 const gboolean same_view = (memcmp(&g->session.live_patch, &view.patch, sizeof(view.patch)) == 0
434 && memcmp(&g->session.live_view_rect, &live_view_rect, sizeof(live_view_rect)) == 0
435 && memcmp(&g->session.preview_rect, &preview_rect, sizeof(preview_rect)) == 0);
436
437 if(same_view)
438 {
439 g->session.last_view_x = dt_dev_viewport_center_x(self->dev);
440 g->session.last_view_y = dt_dev_viewport_center_y(self->dev);
441 g->session.last_view_scale = dt_dev_viewport_scaling(self->dev);
442 return TRUE;
443 }
444
445 g->session.live_patch = view.patch;
446 g->session.live_view_rect = live_view_rect;
447 g->session.preview_rect = preview_rect;
448
450 g->session.last_view_x = dt_dev_viewport_center_x(self->dev);
451 g->session.last_view_y = dt_dev_viewport_center_y(self->dev);
452 g->session.last_view_scale = dt_dev_viewport_scaling(self->dev);
453 return TRUE;
454}
455
457{
458 if(IS_NULL_PTR(self) || IS_NULL_PTR(self->dev) || IS_NULL_PTR(self->dev->pipe)) return;
459 const gboolean was_realtime = dt_dev_pixelpipe_get_realtime(self->dev->pipe);
461 // Leaving realtime mode (commit / abort / focus-loss) drops the transient stroke params so the pipe
462 // renders the committed history state again. Entering does nothing here; heartbeats publish per dab.
463 if(!state)
465 if(was_realtime != state)
467 if(IS_NULL_PTR(self->dev->preview_pipe)) return;
468
469 dt_atomic_set_int(&self->dev->preview_pipe->pause, state ? 1 : 0);
470 if(state)
472}
473
475{
477 if(IS_NULL_PTR(g) || IS_NULL_PTR(self->dev)) return FALSE;
478
479 dt_drawlayer_worker_pause(self, g->stroke.worker);
480 if(!_ensure_widget_cache(self))
481 {
482 dt_drawlayer_worker_resume(self, g->stroke.worker);
483 return FALSE;
484 }
485
486 g->session.live_padding = dt_drawlayer_current_live_padding(self);
487 dt_drawlayer_worker_resume(self, g->stroke.worker);
488 return TRUE;
489}
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
void dt_atomic_set_int(dt_atomic_int *var, int value)
int dt_bauhaus_combobox_length(GtkWidget *widget)
Definition bauhaus.c:1966
void dt_bauhaus_combobox_set(GtkWidget *widget, const int pos)
Definition bauhaus.c:2093
void dt_bauhaus_combobox_remove_at(GtkWidget *widget, int pos)
Definition bauhaus.c:1912
void dt_bauhaus_combobox_add(GtkWidget *widget, const char *text)
Definition bauhaus.c:1827
void dt_control_log(const char *msg,...)
Definition control.c:839
gboolean dt_drawlayer_compute_view_patch(dt_iop_module_t *self, const float padding, drawlayer_view_patch_info_t *view)
gboolean dt_drawlayer_layer_bounds_to_widget_bounds(dt_iop_module_t *self, const float x0, const float y0, const float x1, const float y1, float *left, float *top, float *right, float *bottom)
float dt_drawlayer_current_live_padding(dt_iop_module_t *self)
dt_dev_image_geometry_t dt_dev_geometry_snapshot(const dt_develop_t *dev)
void dt_dev_transient_params_clear(dt_iop_module_t *module)
Drop the transient slot if it belongs to module.
#define dt_dev_pixelpipe_resync_history_main(dev)
float dt_dev_viewport_center_y(const dt_develop_t *dev)
float dt_dev_viewport_center_x(const dt_develop_t *dev)
float dt_dev_viewport_scaling(const dt_develop_t *dev)
GtkWidget * geometry
its size, under the preview
GHashTable * names
GtkWidget* -> the name the application knows it by.
GtkWidget * view
the tree view
void dt_drawlayer_sanitize_params(dt_iop_module_t *self, dt_iop_drawlayer_params_t *params)
Definition drawlayer.c:1546
void dt_drawlayer_release_all_base_patch_extra_refs(dt_iop_drawlayer_gui_data_t *g)
Definition drawlayer.c:466
int64_t dt_drawlayer_sidecar_timestamp_from_path(const char *path)
Definition drawlayer.c:1169
gboolean dt_drawlayer_current_work_profile_key(dt_iop_module_t *self, GList *iop_list, dt_dev_pixelpipe_t *pipe, char *key, const size_t key_size)
Definition drawlayer.c:354
void dt_drawlayer_retain_base_patch_loaded_ref(dt_iop_drawlayer_gui_data_t *g)
Definition drawlayer.c:452
void dt_drawlayer_refresh_layer_widgets(dt_iop_module_t *self)
Definition drawlayer.c:1727
gboolean dt_drawlayer_layer_name_non_empty(const char *name)
Definition drawlayer.c:345
gboolean dt_drawlayer_rekey_shared_base_patch(drawlayer_patch_t *patch, const int32_t imgid, const dt_iop_drawlayer_params_t *params)
Definition drawlayer.c:404
static dt_iop_gui_data_t * dt_iop_gui_data(const struct dt_iop_module_t *m)
The module's GUI data blob, NULL-safe for headless callers: IOP process() implementations read it for...
Definition imageop_gui.h:81
gboolean dt_drawlayer_io_find_layer(const char *path, const char *target_name, const int target_order, dt_drawlayer_io_layer_info_t *info)
Find target layer metadata in sidecar TIFF.
Definition io.c:655
gboolean dt_drawlayer_io_sidecar_path(const int32_t imgid, char *path, const size_t path_size)
Build absolute sidecar path from image id.
Definition io.c:644
gboolean dt_drawlayer_io_list_layer_names(const char *path, char ***names, int *count)
List all TIFF layer page names.
Definition io.c:961
gboolean dt_drawlayer_io_load_layer(const char *path, const char *target_name, const int target_order, const int layer_width, const int layer_height, dt_drawlayer_io_patch_t *patch)
Load one sidecar layer patch into float RGBA destination patch.
Definition io.c:669
gboolean dt_drawlayer_io_store_layer(const char *path, const char *target_name, const int target_order, const char *work_profile, const dt_drawlayer_io_patch_t *patch, const int layer_width, const int layer_height, const gboolean delete_target, int *final_order)
Store/update/delete one layer entry in sidecar TIFF.
Definition io.c:875
void dt_drawlayer_io_free_layer_names(char ***names, int *count)
Free array returned by dt_drawlayer_io_list_layer_names.
Definition io.c:999
TIFF sidecar I/O API for drawlayer layers.
Patch/cache helpers for drawlayer process and preview buffers.
void dt_drawlayer_paint_runtime_state_reset(dt_drawlayer_damaged_rect_t *state)
Reset stroke-damage accumulator to empty/invalid.
gboolean dt_drawlayer_flush_layer_cache(dt_iop_module_t *self)
Definition layers.c:364
gboolean dt_drawlayer_sync_widget_cache(dt_iop_module_t *self)
Definition layers.c:474
void dt_drawlayer_layers_log_errors(GString *errors)
Definition layers.c:42
static gboolean _layer_cache_matches(const dt_iop_drawlayer_gui_data_t *g, const drawlayer_layer_cache_key_t *key)
Definition layers.c:105
void dt_drawlayer_set_pipeline_realtime_mode(dt_iop_module_t *self, const gboolean state)
Definition layers.c:456
void dt_drawlayer_layers_populate_list(dt_iop_module_t *self)
Definition layers.c:48
static gboolean _ensure_widget_cache(dt_iop_module_t *self)
Definition layers.c:409
void dt_drawlayer_layers_reset_stroke_session(dt_iop_drawlayer_gui_data_t *g)
Definition layers.c:94
void dt_drawlayer_layers_append_error(GString *errors, const char *message)
Definition layers.c:35
gboolean dt_drawlayer_ensure_layer_cache(dt_iop_module_t *self)
Definition layers.c:131
The drawlayer's layer store: the layer cache and its sidecar synchronisation.
static const dt_iop_drawlayer_params_t * params
Definition layers.h:80
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t int int * layer_height
Definition layers.h:51
static const dt_dev_pixelpipe_t const dt_dev_pixelpipe_iop_t int * layer_width
Definition layers.h:50
#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
#define DT_PATH_MAX
Buffer size for a filesystem path anywhere in Ansel.
Definition paths.h:57
gboolean dt_dev_pixelpipe_get_realtime(const dt_dev_pixelpipe_t *pipe)
void dt_dev_pixelpipe_set_realtime(dt_dev_pixelpipe_t *pipe, gboolean state)
void dt_drawlayer_process_state_reset_stroke(dt_drawlayer_process_state_t *state)
Definition runtime.c:917
void dt_drawlayer_process_state_invalidate(dt_drawlayer_process_state_t *state)
Definition runtime.c:924
Private runtime state/helpers shared by drawlayer module entrypoints.
void dt_drawlayer_cache_patch_wrunlock(const dt_drawlayer_cache_patch_t *patch)
Release write lock on shared patch cache entry.
void dt_drawlayer_cache_patch_wrlock(const dt_drawlayer_cache_patch_t *patch)
Acquire write lock on shared patch cache entry.
void dt_drawlayer_cache_patch_clear(dt_drawlayer_cache_patch_t *patch, const char *external_alloc_name)
Release patch storage and reset patch metadata.
gboolean dt_drawlayer_cache_ensure_mask_buffer(dt_drawlayer_cache_patch_t *mask, const int width, const int height, const char *name)
Ensure a float stroke-mask buffer exists and matches the requested size.
gboolean dt_drawlayer_cache_patch_alloc_shared(dt_drawlayer_cache_patch_t *patch, const uint64_t hash, const size_t pixel_count, const int width, const int height, const char *name, int *created_out)
Allocate patch storage from shared pixel cache entry.
void dt_drawlayer_cache_patch_rdlock(const dt_drawlayer_cache_patch_t *patch)
Acquire read lock on shared patch cache entry.
void dt_drawlayer_cache_patch_rdunlock(const dt_drawlayer_cache_patch_t *patch)
Release read lock on shared patch cache entry.
void dt_drawlayer_cache_clear_transparent_float(float *pixels, const size_t pixel_count)
Fill float RGBA buffer with transparent black.
#define DRAWLAYER_PROFILE_SIZE
const float uint32_t state[4]
What one sidecar directory scan found about a layer.
Definition layers.h:34
char work_profile[DRAWLAYER_PROFILE_SIZE]
Definition layers.h:41
char name[DRAWLAYER_NAME_SIZE]
Definition layers.h:40
uint32_t height
Definition layers.h:39
const char * layer_name
Definition layers.c:31
Objective facts about the image a dev is working on.
dt_atomic_int pause
dt_atomic_int shutdown
dt_image_t image_storage
Definition develop.h:225
GList * iop
Definition develop.h:269
struct dt_dev_pixelpipe_t * preview_pipe
Definition develop.h:214
struct dt_dev_pixelpipe_t * pipe
Definition develop.h:214
Integer axis-aligned rectangle in buffer coordinates.
Metadata returned when probing one layer directory in sidecar TIFF.
Definition io.h:47
char work_profile[256]
Definition io.h:54
Float RGBA patch used by drawlayer I/O routines.
Definition io.h:37
int32_t id
Definition image.h:410
struct dt_develop_t * dev
Definition imageop.h:311
dt_iop_params_t * params
Definition imageop.h:333
Telling the user something happened.
#define dt_gui_widget_freeze()
void dt_drawlayer_worker_reset_backend_path(dt_drawlayer_worker_t *worker)
Reset worker-owned backend damage accumulator.
Definition worker.c:1784
gboolean dt_drawlayer_worker_wait_idle(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Wait until worker queue is drained and not busy.
Definition worker.c:1415
void dt_drawlayer_worker_pause(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Pause worker processing after current callback returns.
Definition worker.c:1600
gboolean dt_drawlayer_worker_any_active(const dt_drawlayer_worker_t *worker)
Public status query: TRUE when any worker still has pending activity.
Definition worker.c:1722
void dt_drawlayer_worker_reset_live_publish(dt_drawlayer_worker_t *worker)
Reset worker-owned transient live-publish state.
Definition worker.c:1792
void dt_drawlayer_worker_resume(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Resume worker processing and wake sleeping thread.
Definition worker.c:1615
Background stroke worker API for drawlayer realtime painting.