Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
runtime.c
Go to the documentation of this file.
1/*
2 This file is part of the Ansel project.
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 Ansel. If not, see <http://www.gnu.org/licenses/>.
17*/
18
19#include "iop/drawlayer/cache.h"
21#include "control/control.h"
23#include "develop/develop.h"
24
25#include <string.h>
26
37
44
56
61
63{
64 return state ? state->priv : NULL;
65}
66
68 const gboolean resident, const gboolean valid, const gboolean dirty)
69{
71 if(IS_NULL_PTR(priv) || buffer >= DT_DRAWLAYER_RUNTIME_BUFFER_COUNT) return;
72 priv->buffers[buffer].resident = resident;
73 priv->buffers[buffer].valid = valid;
74 priv->buffers[buffer].dirty = dirty;
75}
76
78{
79 if(IS_NULL_PTR(state)) return;
80 memset(state, 0, sizeof(*state));
81 state->priv = g_malloc0(sizeof(*state->priv));
82 if(state->priv) dt_pthread_mutex_init(&state->priv->mutex, NULL);
83}
84
86{
87 if(IS_NULL_PTR(state)) return;
88 if(state->priv)
89 {
90 dt_pthread_mutex_destroy(&state->priv->mutex);
91 dt_free(state->priv);
92 }
93 memset(state, 0, sizeof(*state));
94}
95
99 const gboolean write_lock,
100 const gboolean acquire)
101{
103 if(IS_NULL_PTR(priv) || buffer >= DT_DRAWLAYER_RUNTIME_BUFFER_COUNT) return;
105 dt_drawlayer_runtime_buffer_state_t *entry = &priv->buffers[buffer];
106
107 if(write_lock)
108 {
109 entry->write_locked = acquire;
110 entry->writer = acquire ? actor : DT_DRAWLAYER_RUNTIME_ACTOR_NONE;
111 }
112 else if(acquire)
113 {
114 entry->read_locks++;
115 entry->last_reader = actor;
116 }
117 else if(entry->read_locks > 0)
118 {
119 entry->read_locks--;
121 }
123}
124
126 const dt_drawlayer_worker_snapshot_t *worker_snapshot,
128{
129 if(inputs) *inputs = (dt_drawlayer_runtime_inputs_t){ 0 };
130 if(IS_NULL_PTR(runtime) || IS_NULL_PTR(inputs)) return;
131
132 const dt_drawlayer_runtime_request_t *const request = &runtime->runtime;
133 dt_iop_module_t *const self = request->self;
134 dt_iop_drawlayer_gui_data_t *const g = request->gui;
135 dt_drawlayer_process_state_t *const process = request->process_state ? request->process_state : (g ? &g->process : NULL);
136 const dt_iop_drawlayer_params_t *const runtime_params
137 = request->runtime_params ? request->runtime_params : (const dt_iop_drawlayer_params_t *)self->params;
138
140 .session = g ? &g->session : NULL,
141 .process = process,
142 .stroke = g ? &g->stroke : NULL,
143 .worker = worker_snapshot,
144 .base_patch = NULL,
145 .base_patch_valid = FALSE,
146 .base_patch_dirty = FALSE,
147 .painting_active = g && g->manager.painting_active,
148 .gui_attached = self && self->dev && self->dev->gui_attached && g,
149 .module_focused = self && self->dev && self->dev->gui_module == self,
150 .display_pipe = request->display_pipe,
151 .have_layer_selection = runtime_params && runtime_params->layer_name[0] != '\0',
152 .selected_layer_name = runtime_params ? runtime_params->layer_name : NULL,
153 .selected_layer_order = runtime_params ? runtime_params->layer_order : -1,
154 .have_valid_output_roi = request->roi_out && request->roi_out->width > 0 && request->roi_out->height > 0,
155 .use_opencl = request->use_opencl,
156 .view_changed = g && self && self->dev
157 && (fabsf(g->session.last_view_x - dt_dev_viewport_center_x(self->dev)) > 1e-6f
158 || fabsf(g->session.last_view_y - dt_dev_viewport_center_y(self->dev)) > 1e-6f
159 || fabsf(g->session.last_view_scale - dt_dev_viewport_scaling(self->dev)) > 1e-6f),
160 .padding_changed = g && self && fabsf(g->session.live_padding - dt_drawlayer_current_live_padding(self)) > 1e-6f,
161 };
162}
163
165 const dt_drawlayer_runtime_context_t *context,
167 dt_drawlayer_worker_snapshot_t *worker_snapshot)
168{
169 if(inputs) *inputs = (dt_drawlayer_runtime_inputs_t){ 0 };
170 if(worker_snapshot) *worker_snapshot = (dt_drawlayer_worker_snapshot_t){ 0 };
171 if(!IS_NULL_PTR(request) && request->inputs)
172 {
173 if(!IS_NULL_PTR(inputs)) *inputs = *request->inputs;
174 return;
175 }
176 if(!IS_NULL_PTR(context) && context->runtime.gui && context->runtime.gui->stroke.worker && !IS_NULL_PTR(worker_snapshot))
177 dt_drawlayer_worker_get_snapshot(context->runtime.gui->stroke.worker, worker_snapshot);
178 _fill_runtime_inputs(context, worker_snapshot, inputs);
179}
180
182 const dt_drawlayer_runtime_inputs_t *inputs)
183{
185 const dt_drawlayer_process_state_t *process = inputs ? inputs->process : NULL;
186 const dt_drawlayer_worker_snapshot_t *worker = inputs ? inputs->worker : NULL;
187 const dt_drawlayer_cache_patch_t *base_patch = inputs ? inputs->base_patch : NULL;
188
189 if(IS_NULL_PTR(priv)) return;
190 state->painting_active = inputs && inputs->painting_active;
191
192 if(!IS_NULL_PTR(process))
193 {
194 priv->layer_cache_valid = process->cache_valid;
196 process->cache_valid, process->cache_dirty);
198 !IS_NULL_PTR(process->stroke_mask.pixels), FALSE);
199 }
200 else if(!IS_NULL_PTR(base_patch))
201 {
202 priv->layer_cache_valid = inputs->base_patch_valid;
204 inputs->base_patch_valid, inputs->base_patch_dirty);
205 }
206
207 if(!IS_NULL_PTR(worker))
208 {
209 const gboolean backend_started = worker->backend_state != DT_DRAWLAYER_WORKER_STATE_STOPPED;
210 const gboolean backend_busy = worker->backend_state == DT_DRAWLAYER_WORKER_STATE_BUSY;
211 const gboolean backend_waiting = (worker->backend_state == DT_DRAWLAYER_WORKER_STATE_PAUSING
213 const gboolean backend_active = backend_started
214 && (backend_busy || worker->backend_queue_count > 0
215 || worker->commit_pending || state->painting_active);
219 }
220}
221
224 const dt_drawlayer_runtime_inputs_t *inputs)
225{
227 if(IS_NULL_PTR(state) || IS_NULL_PTR(request)) return;
228 if(IS_NULL_PTR(priv)) return;
229
230 priv->last_event = request->event;
231 priv->last_raw_input_kind = request->raw_input_kind;
232
233 switch(request->event)
234 {
236 priv->gui_focused = TRUE;
239 break;
240
242 priv->gui_focused = FALSE;
245 break;
246
250 break;
251
260 break;
261
264 = priv->gui_focused && inputs && inputs->gui_attached;
266 break;
267
271 break;
272
276 break;
277
281 break;
282
286 break;
287
290 priv->sidecar_io_active = TRUE;
293 break;
294
297 priv->sidecar_io_active = FALSE;
300 break;
301
305 break;
306
309 = priv->gui_focused && inputs && inputs->gui_attached;
311 break;
312
314 default:
315 break;
316 }
317
318 const gboolean painting_before = state->painting_active;
320 {
322 state->painting_active = TRUE;
324 state->painting_active = FALSE;
325 }
329 {
330 state->painting_active = FALSE;
331 }
332 if(painting_before != state->painting_active)
333 dt_print(DT_DEBUG_PERF, "[drawlayer] painting_active %d->%d by event=%d raw_kind=%d\n",
334 painting_before, state->painting_active, request->event, request->raw_input_kind);
335}
336
339 const dt_drawlayer_runtime_inputs_t *inputs)
340{
342 if(IS_NULL_PTR(state)) return;
343 if(IS_NULL_PTR(priv)) return;
344
345 gboolean realtime_active = priv->gui_focused && inputs && inputs->gui_attached
346 && state->painting_active;
347
348 if(!IS_NULL_PTR(request))
349 {
350 switch(request->event)
351 {
356 realtime_active = FALSE;
357 break;
358
360 // Realtime mode tracks painting_active only (set by _apply_runtime_event on STROKE_BEGIN/END,
361 // which runs just before this). A SAMPLE raw-input also fires on plain hover (cursor tracking)
362 // while NOT painting; forcing realtime on there toggled it on/off against every pipe-finished,
363 // and each flip paid a full resync_history_main (~44ms). Fall through to the base computation so
364 // hover never enters realtime and only an actual stroke does.
365 break;
366
383 default:
384 break;
385 }
386 }
387
388 state->realtime_active = realtime_active;
389}
390
411
414 const dt_drawlayer_runtime_host_t *host,
416
419 const dt_drawlayer_runtime_host_t *host,
420 const dt_drawlayer_runtime_commit_mode_t commit_mode,
422{
423 if(commit_mode == DT_DRAWLAYER_RUNTIME_COMMIT_NONE) return TRUE;
424 const dt_drawlayer_runtime_context_t *const context
425 = host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL;
426 if(IS_NULL_PTR(context) || !context->runtime.self || !context->runtime.gui) return FALSE;
427
430 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
431 .inputs = request ? request->inputs : NULL,
432 };
433 _update_manager_information(state, &begin, host, NULL);
436
439 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
440 .inputs = request ? request->inputs : NULL,
441 };
442 _update_manager_information(state, &end, host, NULL);
444 return TRUE;
445}
446
449{
450 const dt_drawlayer_runtime_context_t *const context
451 = host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL;
452 (void)result;
453 if(IS_NULL_PTR(context) || !context->runtime.self) return FALSE;
456}
457
461
464 const dt_drawlayer_runtime_inputs_t *inputs,
466{
468 if(schedule)
472 };
473 const dt_drawlayer_process_state_t *process = inputs ? inputs->process : NULL;
474 const dt_drawlayer_stroke_state_t *stroke = inputs ? inputs->stroke : NULL;
475 if(IS_NULL_PTR(schedule) || IS_NULL_PTR(inputs) || IS_NULL_PTR(request) || IS_NULL_PTR(priv)) return;
476
477 const gboolean layer_selection_changed
478 = inputs->have_layer_selection && process
479 && (!process->cache_valid || g_strcmp0(process->cache_layer_name,
480 inputs->selected_layer_name ? inputs->selected_layer_name : "")
481 || (process->cache_layer_order >= 0 && inputs->selected_layer_order >= 0
482 && process->cache_layer_order != inputs->selected_layer_order));
483
485
486 const gboolean backend_busy = priv->threads[DT_DRAWLAYER_RUNTIME_ACTOR_RASTER_BACKEND].active;
487 const gboolean have_pending_stroke_work
488 = (state->painting_active || (stroke && (stroke->finish_commit_pending || stroke->stroke_sample_count > 0)))
489 || backend_busy;
490 const gboolean have_pending_gui_stroke_work
491 = state->painting_active || (stroke && stroke->stroke_sample_count > 0);
492 const gboolean have_pending_cache_writes = process && process->cache_dirty;
493
494 switch(request->event)
495 {
497 schedule->sync_realtime_mode = TRUE;
498 schedule->ensure_worker_running = inputs->module_focused;
499 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
500 break;
501
503 schedule->sync_realtime_mode = TRUE;
504 schedule->feedback = schedule->rasterization_busy
507 schedule->commit_mode = have_pending_stroke_work
510 schedule->flush_sidecar = have_pending_cache_writes && process && process->cache_valid;
511 schedule->stop_worker = TRUE;
512 break;
513
515 schedule->set_pointer_state = TRUE;
516 schedule->pointer_valid = TRUE;
517 schedule->pointer_hide_cursor = TRUE;
518 break;
519
521 schedule->sync_realtime_mode = TRUE;
522 schedule->set_pointer_state = TRUE;
523 schedule->pointer_valid = FALSE;
524 schedule->pointer_hide_cursor = FALSE;
525 schedule->queue_redraw_center = TRUE;
526 break;
527
529 schedule->commit_mode = have_pending_gui_stroke_work ? DT_DRAWLAYER_RUNTIME_COMMIT_QUIET
531 schedule->sync_widget_cache = TRUE;
532 schedule->queue_redraw_center = TRUE;
533 break;
534
536 schedule->commit_mode = (request->flush_pending && have_pending_gui_stroke_work)
539 schedule->invalidate_layer_cache = layer_selection_changed;
540 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
541 schedule->ensure_worker_running = inputs->module_focused && inputs->have_layer_selection;
542 break;
543
545 schedule->sync_realtime_mode = TRUE;
546 schedule->commit_mode = have_pending_stroke_work
549 schedule->flush_sidecar = process && process->cache_valid;
550 schedule->stop_worker = TRUE;
551 schedule->invalidate_layer_cache = TRUE;
552 schedule->refresh_gui = TRUE;
553 schedule->sync_widget_cache = TRUE;
554 schedule->ensure_worker_running = inputs->module_focused;
555 break;
556
558 schedule->invalidate_layer_cache = layer_selection_changed;
559 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
560 schedule->ensure_worker_running = inputs->module_focused && inputs->have_layer_selection;
561 break;
562
564 schedule->sync_widget_cache = (inputs->view_changed || inputs->padding_changed)
565 && !state->painting_active && !schedule->rasterization_busy;
566 break;
567
569 schedule->sync_realtime_mode = TRUE;
570 schedule->request_commit = TRUE;
571 break;
572
574 switch(request->raw_input_kind)
575 {
577 schedule->sync_realtime_mode = TRUE;
578 /* A new GUI stroke must first finish any previous stroke that was
579 * still draining/committing. Use the pre-event GUI state from
580 * `inputs`, not the post-event manager state, because `_apply_runtime_event()`
581 * already flipped `state->painting_active` to TRUE for the new stroke. */
582 schedule->commit_mode = (!inputs->painting_active
583 && ((stroke && (stroke->finish_commit_pending || stroke->stroke_sample_count > 0))
584 || backend_busy))
587 schedule->sync_widget_cache = TRUE;
588 schedule->ensure_worker_running = TRUE;
589 schedule->queue_raw_input = TRUE;
590 break;
591
593 schedule->sync_realtime_mode = TRUE;
594 schedule->ensure_worker_running = state->painting_active;
595 schedule->queue_raw_input = state->painting_active;
596 break;
597
599 schedule->sync_realtime_mode = FALSE;
600 schedule->ensure_worker_running = TRUE;
601 schedule->request_commit = TRUE;
602 schedule->queue_raw_input = TRUE;
603 break;
604
606 default:
607 schedule->sync_realtime_mode = TRUE;
608 break;
609 }
610 break;
611
613 schedule->ensure_layer_cache = inputs->display_pipe && inputs->have_layer_selection
614 && !priv->layer_cache_valid;
615 break;
616
618 schedule->ensure_layer_cache = inputs->display_pipe && inputs->have_layer_selection
619 && !priv->layer_cache_valid;
620 break;
621
631 default:
632 break;
633 }
634}
635
638 const dt_drawlayer_runtime_host_t *host,
640{
641 if(schedule) *schedule = (dt_drawlayer_runtime_schedule_t){ 0 };
642 if(IS_NULL_PTR(state)) return;
643
644 dt_drawlayer_runtime_inputs_t inputs = { 0 };
645 dt_drawlayer_worker_snapshot_t worker_snapshot = { 0 };
646 _collect_runtime_inputs(request, host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL,
647 &inputs, &worker_snapshot);
648
650 if(IS_NULL_PTR(priv)) return;
651 dt_pthread_mutex_lock(&priv->mutex);
653 if(request) _apply_runtime_event(state, request, &inputs);
654 _update_realtime_state(state, request, &inputs);
655 _build_runtime_schedule(state, request, &inputs, schedule);
656 dt_pthread_mutex_unlock(&priv->mutex);
657}
658
661 const dt_drawlayer_runtime_host_t *host)
662{
664 .ok = TRUE,
665 .raw_input_ok = TRUE,
666 };
667 if(IS_NULL_PTR(state) || IS_NULL_PTR(request) || IS_NULL_PTR(host)) return result;
668 const dt_drawlayer_runtime_context_t *const context
670 if(IS_NULL_PTR(context)) return result;
671
672 dt_iop_module_t *const self = context->runtime.self;
673 dt_iop_drawlayer_gui_data_t *const g = context->runtime.gui;
674
675 dt_drawlayer_runtime_schedule_t schedule = { 0 };
676 _update_manager_information(state, request, host, &schedule);
677
678 if(schedule.sync_realtime_mode && self && g)
679 dt_drawlayer_set_pipeline_realtime_mode(self, g->manager.realtime_active);
680
681 switch(request->event)
682 {
684 if(schedule.ensure_worker_running && self && g
685 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
686 {
687 dt_control_log(_("failed to start drawing worker"));
688 result.ok = FALSE;
689 }
690 if(schedule.sync_widget_cache && result.ok
691 && !_perform_runtime_widget_cache_sync(host, &result))
692 result.ok = FALSE;
693 break;
694
697 if(schedule.set_pointer_state && g)
698 {
699 g->session.pointer_valid = schedule.pointer_valid;
701 }
703 break;
704
708 if(result.ok
709 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
710 result.ok = FALSE;
711 if(schedule.invalidate_layer_cache && g)
712 {
714 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
715 g->process.cache_valid = FALSE;
716 g->process.cache_dirty = FALSE;
717 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
718 g->process.cache_imgid = -1;
719 g->process.cache_layer_name[0] = '\0';
720 g->process.cache_layer_order = -1;
722 }
723 if(result.ok && schedule.sync_widget_cache
724 && !_perform_runtime_widget_cache_sync(host, &result))
725 result.ok = FALSE;
726 if(result.ok && schedule.ensure_worker_running && self && g
727 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
728 {
729 dt_control_log(_("failed to start drawing worker"));
730 result.ok = FALSE;
731 }
733 break;
734
736 if(schedule.sync_widget_cache && !_perform_runtime_widget_cache_sync(host, &result)) result.ok = FALSE;
737 break;
738
741 if(schedule.request_commit && g) dt_drawlayer_worker_request_commit(g->stroke.worker);
742 break;
743
746 if(result.ok
747 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
748 result.ok = FALSE;
749 if(result.ok && schedule.feedback != DT_DRAWLAYER_RUNTIME_FEEDBACK_NONE && g)
751 if(schedule.flush_sidecar)
752 {
755 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
756 .inputs = request->inputs,
757 };
758 _update_manager_information(state, &begin, host, NULL);
759 if(self && !dt_drawlayer_flush_layer_cache(self))
760 {
761 dt_control_alert(_("Drawing not saved"), _("failed to write drawing layer sidecar"), NULL);
762 result.ok = FALSE;
763 }
766 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
767 .inputs = request->inputs,
768 };
769 _update_manager_information(state, &end, host, NULL);
770 }
771 if(schedule.stop_worker && self && g) dt_drawlayer_worker_stop(self, g->stroke.worker);
772 if(schedule.invalidate_layer_cache && g)
773 {
775 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
776 g->process.cache_valid = FALSE;
777 g->process.cache_dirty = FALSE;
778 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
780 }
781 if(schedule.refresh_gui && self) gui_update(self);
782 if(schedule.sync_widget_cache && result.ok
783 && !_perform_runtime_widget_cache_sync(host, &result))
784 result.ok = FALSE;
785 if(schedule.ensure_worker_running && self && g
786 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
787 {
788 dt_control_log(_("failed to start drawing worker"));
789 result.ok = FALSE;
790 }
791 break;
792
795 {
796 if(result.ok
797 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
798 result.ok = FALSE;
799 if(result.ok && schedule.sync_widget_cache
800 && !_perform_runtime_widget_cache_sync(host, &result))
801 result.ok = FALSE;
802 if(result.ok && schedule.ensure_worker_running && self && g)
803 {
804 if(!dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
805 {
806 dt_control_log(_("failed to start drawing worker"));
807 result.ok = FALSE;
808 }
809 }
810 if(result.ok && self) dt_drawlayer_begin_gui_stroke_capture(self, context->raw_input);
811 }
814
815 if(result.ok && schedule.ensure_worker_running && self && g
817 {
818 if(!dt_drawlayer_worker_ensure_running(self, g->stroke.worker)
820 {
821 dt_control_log(_("failed to start drawing worker"));
822 result.ok = FALSE;
823 }
824 }
825
826 if(schedule.request_commit && g) dt_drawlayer_worker_request_commit(g->stroke.worker);
827
828 if(schedule.queue_raw_input && g)
829 {
830 gboolean ok = TRUE;
831 if(IS_NULL_PTR(context->raw_input))
832 ok = FALSE;
834 ok = dt_drawlayer_worker_enqueue_stroke_end(g->stroke.worker, context->raw_input);
837 ok = dt_drawlayer_worker_enqueue_input(g->stroke.worker, context->raw_input);
838 result.raw_input_ok = ok;
839 }
840 break;
841
844 if(schedule.ensure_layer_cache)
845 {
848 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
849 .inputs = request->inputs,
850 };
851 _update_manager_information(state, &begin, host, NULL);
852 if(self && !dt_drawlayer_ensure_layer_cache(self)) result.ok = FALSE;
855 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
856 .inputs = request->inputs,
857 };
858 _update_manager_information(state, &end, host, NULL);
859 }
860 break;
861
871 default:
872 break;
873 }
874
875 if(request->release.source)
877
878 _update_manager_information(state, request->inputs ? request : NULL, host, NULL);
879 if(schedule.sync_realtime_mode && self && g)
880 dt_drawlayer_set_pipeline_realtime_mode(self, g->manager.realtime_active);
881
882 return result;
883}
884
886 dt_drawlayer_process_state_t *headless_process,
888 dt_drawlayer_process_state_t *gui_process,
889 const gboolean display_pipe,
890 dt_drawlayer_runtime_manager_t **runtime_manager,
891 dt_drawlayer_process_state_t **runtime_process,
892 gboolean *runtime_display_pipe)
893{
894 if(!IS_NULL_PTR(runtime_manager)) *runtime_manager = display_pipe ? gui_manager : headless_manager;
895 if(!IS_NULL_PTR(runtime_process)) *runtime_process = display_pipe ? gui_process : headless_process;
896 if(!IS_NULL_PTR(runtime_display_pipe)) *runtime_display_pipe = display_pipe;
897}
898
900{
901 if(IS_NULL_PTR(state)) return;
902 memset(state, 0, sizeof(*state));
903 state->cache_imgid = -1;
904 state->cache_layer_order = -1;
905}
906
908{
909 if(IS_NULL_PTR(state)) return;
910 dt_drawlayer_cache_patch_clear(&state->base_patch, "drawlayer patch");
911 dt_drawlayer_cache_patch_clear(&state->stroke_mask, "drawlayer patch");
912 memset(state, 0, sizeof(*state));
913 state->cache_imgid = -1;
914 state->cache_layer_order = -1;
915}
916
918{
919 if(IS_NULL_PTR(state)) return;
920 if(state->stroke_mask.pixels)
921 memset(state->stroke_mask.pixels, 0, (size_t)state->stroke_mask.width * state->stroke_mask.height * sizeof(float));
922}
923
925{
926 if(IS_NULL_PTR(state)) return;
927 dt_drawlayer_cache_patch_clear(&state->stroke_mask, "drawlayer stroke mask");
928 /* Any state invalidation may relocate/free the output buffer this tracked, so
929 * the realtime partial-composite fast path can no longer trust it. */
930 state->last_composite_valid = FALSE;
931 state->last_composite_dev_out = NULL;
932}
933
937{
938 if(IS_NULL_PTR(source)) return;
939
940 if(state && source->tracked_read_lock)
942 FALSE);
943
944 switch(source->kind)
945 {
948 break;
949
951 default:
952 break;
953 }
954
955 *source = (dt_drawlayer_runtime_source_t){ 0 };
956}
957
959{
960 if(IS_NULL_PTR(state)) return;
961 if(state->cursor_surface)
962 {
963 cairo_surface_destroy(state->cursor_surface);
964 state->cursor_surface = NULL;
965 }
966 state->cursor_surface_size = 0;
967 state->cursor_surface_ppd = 0.0;
968 state->cursor_radius = 0.0f;
969 state->cursor_opacity = 0.0f;
970 state->cursor_hardness = 0.0f;
971 state->cursor_shape = -1;
972 state->cursor_color[0] = state->cursor_color[1] = state->cursor_color[2] = -1.0f;
973}
__DT_CLONE_TARGETS__ int process(struct dt_iop_module_t *self, const dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition ashift.c:3179
void gui_update(struct dt_iop_module_t *self)
Definition ashift.c:5736
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
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
void dt_control_log(const char *msg,...)
Definition control.c:839
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:970
#define dt_control_set_cursor_visible(visible)
Definition control.h:153
float dt_drawlayer_current_live_padding(dt_iop_module_t *self)
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)
gboolean dt_drawlayer_flush_layer_cache(dt_iop_module_t *self)
Definition layers.c:364
void dt_drawlayer_show_runtime_feedback(const dt_iop_drawlayer_gui_data_t *g, const dt_drawlayer_runtime_feedback_t feedback)
Definition drawlayer.c:2736
gboolean dt_drawlayer_sync_widget_cache(dt_iop_module_t *self)
Definition layers.c:474
void dt_drawlayer_begin_gui_stroke_capture(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *first_input)
Definition drawlayer.c:2669
void dt_drawlayer_release_all_base_patch_extra_refs(dt_iop_drawlayer_gui_data_t *g)
Definition drawlayer.c:466
gboolean dt_drawlayer_commit_dabs(dt_iop_module_t *self, gboolean record_history)
Definition drawlayer.c:1804
void dt_drawlayer_set_pipeline_realtime_mode(dt_iop_module_t *self, gboolean state)
Definition layers.c:456
void dt_drawlayer_end_gui_stroke_capture(dt_iop_module_t *self)
Definition drawlayer.c:2697
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_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Initialise a mutex. With mutexattr NULL – which is how 54 of the 56 call sites in this tree spell it ...
Definition dtpthread.h:104
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:132
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:117
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.
@ DT_DEBUG_PERF
Definition logging.h:55
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
static void _release_runtime_source(dt_drawlayer_runtime_manager_t *state, dt_drawlayer_process_state_t *process, dt_drawlayer_runtime_source_t *source)
Definition runtime.c:934
void dt_drawlayer_runtime_manager_bind_piece(dt_drawlayer_runtime_manager_t *headless_manager, dt_drawlayer_process_state_t *headless_process, dt_drawlayer_runtime_manager_t *gui_manager, dt_drawlayer_process_state_t *gui_process, const gboolean display_pipe, dt_drawlayer_runtime_manager_t **runtime_manager, dt_drawlayer_process_state_t **runtime_process, gboolean *runtime_display_pipe)
Definition runtime.c:885
void dt_drawlayer_runtime_manager_cleanup(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:85
static const dt_drawlayer_runtime_private_t * _runtime_private_const(const dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:62
void dt_drawlayer_runtime_manager_init(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:77
dt_drawlayer_runtime_result_t dt_drawlayer_runtime_manager_update(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_host_t *host)
Definition runtime.c:659
void dt_drawlayer_process_state_reset_stroke(dt_drawlayer_process_state_t *state)
Definition runtime.c:917
void dt_drawlayer_process_state_init(dt_drawlayer_process_state_t *state)
Definition runtime.c:899
static gboolean _perform_runtime_commit_sequence(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_host_t *host, const dt_drawlayer_runtime_commit_mode_t commit_mode, dt_drawlayer_runtime_result_t *result)
Definition runtime.c:417
void dt_drawlayer_ui_cursor_clear(dt_drawlayer_ui_state_t *state)
Definition runtime.c:958
void dt_drawlayer_process_state_cleanup(dt_drawlayer_process_state_t *state)
Definition runtime.c:907
void dt_drawlayer_runtime_manager_note_buffer_lock(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_buffer_t buffer, const dt_drawlayer_runtime_actor_t actor, const gboolean write_lock, const gboolean acquire)
Definition runtime.c:96
static gboolean _perform_runtime_widget_cache_sync(const dt_drawlayer_runtime_host_t *host, dt_drawlayer_runtime_result_t *result)
Definition runtime.c:447
static void _sync_runtime_state_from_inputs(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_inputs_t *inputs)
Definition runtime.c:181
static dt_drawlayer_runtime_private_t * _runtime_private(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:57
void dt_drawlayer_process_state_invalidate(dt_drawlayer_process_state_t *state)
Definition runtime.c:924
static void _update_realtime_state(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_inputs_t *inputs)
Definition runtime.c:337
static void _update_manager_information(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_host_t *host, dt_drawlayer_runtime_schedule_t *schedule)
Definition runtime.c:636
static void _fill_runtime_inputs(const dt_drawlayer_runtime_context_t *runtime, const dt_drawlayer_worker_snapshot_t *worker_snapshot, dt_drawlayer_runtime_inputs_t *inputs)
Definition runtime.c:125
static void _sync_buffer_state(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_buffer_t buffer, const gboolean resident, const gboolean valid, const gboolean dirty)
Definition runtime.c:67
static void _collect_runtime_inputs(const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_context_t *context, dt_drawlayer_runtime_inputs_t *inputs, dt_drawlayer_worker_snapshot_t *worker_snapshot)
Definition runtime.c:164
static void _apply_runtime_event(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_inputs_t *inputs)
Definition runtime.c:222
static void _build_runtime_schedule(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_update_request_t *request, const dt_drawlayer_runtime_inputs_t *inputs, dt_drawlayer_runtime_schedule_t *schedule)
Definition runtime.c:462
Private runtime state/helpers shared by drawlayer module entrypoints.
dt_drawlayer_runtime_raw_input_kind_t
Definition runtime.h:231
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE
Definition runtime.h:232
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_BEGIN
Definition runtime.h:234
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_END
Definition runtime.h:235
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_SAMPLE
Definition runtime.h:233
@ DT_DRAWLAYER_SOURCE_BASE_PATCH
Definition runtime.h:335
@ DT_DRAWLAYER_SOURCE_NONE
Definition runtime.h:334
dt_drawlayer_runtime_actor_t
Definition runtime.h:187
@ DT_DRAWLAYER_RUNTIME_ACTOR_GUI
Definition runtime.h:189
@ DT_DRAWLAYER_RUNTIME_ACTOR_RASTER_BACKEND
Definition runtime.h:192
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CPU
Definition runtime.h:190
@ DT_DRAWLAYER_RUNTIME_ACTOR_COUNT
Definition runtime.h:194
@ DT_DRAWLAYER_RUNTIME_ACTOR_TIFF_IO
Definition runtime.h:193
@ DT_DRAWLAYER_RUNTIME_ACTOR_NONE
Definition runtime.h:188
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CL
Definition runtime.h:191
dt_drawlayer_runtime_commit_mode_t
Definition runtime.h:239
@ DT_DRAWLAYER_RUNTIME_COMMIT_HISTORY
Definition runtime.h:242
@ DT_DRAWLAYER_RUNTIME_COMMIT_QUIET
Definition runtime.h:241
@ DT_DRAWLAYER_RUNTIME_COMMIT_NONE
Definition runtime.h:240
dt_drawlayer_runtime_buffer_t
Definition runtime.h:198
@ DT_DRAWLAYER_RUNTIME_BUFFER_COUNT
Definition runtime.h:201
@ DT_DRAWLAYER_RUNTIME_BUFFER_BASE_PATCH
Definition runtime.h:199
@ DT_DRAWLAYER_RUNTIME_BUFFER_STROKE_MASK
Definition runtime.h:200
dt_drawlayer_runtime_event_t
Definition runtime.h:205
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_LOAD_END
Definition runtime.h:223
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_GAIN
Definition runtime.h:207
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_LOAD_BEGIN
Definition runtime.h:222
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC
Definition runtime.h:214
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_AFTER
Definition runtime.h:219
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SCROLL
Definition runtime.h:211
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_BEFORE
Definition runtime.h:220
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_PIPE_FINISHED
Definition runtime.h:215
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_AFTER
Definition runtime.h:221
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_CHANGE_IMAGE
Definition runtime.h:213
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RAW_INPUT
Definition runtime.h:217
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_BEFORE
Definition runtime.h:218
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_SAVE_END
Definition runtime.h:225
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_LEAVE
Definition runtime.h:210
@ DT_DRAWLAYER_RUNTIME_EVENT_COMMIT_BEGIN
Definition runtime.h:226
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT
Definition runtime.h:216
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_ENTER
Definition runtime.h:209
@ DT_DRAWLAYER_RUNTIME_EVENT_COMMIT_END
Definition runtime.h:227
@ DT_DRAWLAYER_RUNTIME_EVENT_NONE
Definition runtime.h:206
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_SAVE_BEGIN
Definition runtime.h:224
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_LOSS
Definition runtime.h:208
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SYNC_TEMP_BUFFERS
Definition runtime.h:212
void dt_drawlayer_cache_patch_clear(dt_drawlayer_cache_patch_t *patch, const char *external_alloc_name)
Release patch storage and reset patch metadata.
void dt_drawlayer_cache_patch_rdunlock(const dt_drawlayer_cache_patch_t *patch)
Release read lock on shared patch cache entry.
Shared drawlayer runtime helpers used across module/runtime files.
dt_drawlayer_runtime_feedback_t
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_NONE
@ DT_DRAWLAYER_RUNTIME_FEEDBACK_FOCUS_LOSS_WAIT
gboolean dt_drawlayer_ensure_layer_cache(dt_iop_module_t *self)
Definition layers.c:131
const float uint32_t state[4]
int32_t gui_attached
Definition develop.h:167
struct dt_iop_module_t * gui_module
Definition develop.h:170
Generic float RGBA patch stored either in malloc memory or pixel cache.
dt_drawlayer_runtime_actor_t writer
Definition runtime.c:35
dt_drawlayer_runtime_actor_t last_reader
Definition runtime.c:33
const dt_drawlayer_paint_raw_input_t * raw_input
Definition runtime.h:324
dt_drawlayer_runtime_request_t runtime
Definition runtime.h:323
What the runtime manager is given to reach its caller's state.
Definition runtime.h:292
const dt_drawlayer_stroke_state_t * stroke
Definition runtime.h:264
const dt_drawlayer_session_state_t * session
Definition runtime.h:262
const char * selected_layer_name
Definition runtime.h:274
const dt_drawlayer_worker_snapshot_t * worker
Definition runtime.h:265
const dt_drawlayer_cache_patch_t * base_patch
Definition runtime.h:266
const dt_drawlayer_process_state_t * process
Definition runtime.h:263
dt_drawlayer_runtime_buffer_state_t buffers[DT_DRAWLAYER_RUNTIME_BUFFER_COUNT]
Definition runtime.c:48
dt_drawlayer_runtime_event_t last_event
Definition runtime.c:53
dt_drawlayer_runtime_thread_state_t threads[DT_DRAWLAYER_RUNTIME_ACTOR_COUNT]
Definition runtime.c:49
dt_pthread_mutex_t mutex
Definition runtime.c:47
dt_drawlayer_runtime_raw_input_kind_t last_raw_input_kind
Definition runtime.c:54
dt_drawlayer_runtime_source_t * source
Definition runtime.h:356
dt_drawlayer_process_state_t * process
Definition runtime.h:355
const dt_iop_drawlayer_params_t * runtime_params
Definition runtime.h:311
dt_iop_module_t * self
Definition runtime.h:308
dt_iop_drawlayer_gui_data_t * gui
Definition runtime.h:312
dt_drawlayer_process_state_t * process_state
Definition runtime.h:314
const dt_iop_roi_t * roi_out
Definition runtime.h:317
dt_drawlayer_runtime_commit_mode_t commit_mode
Definition runtime.c:393
dt_drawlayer_runtime_feedback_t feedback
Definition runtime.c:395
dt_drawlayer_runtime_buffer_t tracked_buffer
Definition runtime.h:348
dt_drawlayer_runtime_source_kind_t kind
Definition runtime.h:340
dt_drawlayer_runtime_actor_t tracked_actor
Definition runtime.h:349
const dt_drawlayer_runtime_inputs_t * inputs
Definition runtime.h:363
dt_drawlayer_runtime_event_t event
Definition runtime.h:361
dt_drawlayer_runtime_release_t release
Definition runtime.h:365
dt_drawlayer_runtime_raw_input_kind_t raw_input_kind
Definition runtime.h:362
dt_drawlayer_worker_t * worker
Definition runtime.h:74
dt_drawlayer_worker_state_t backend_state
Definition worker.h:43
dt_drawlayer_stroke_state_t stroke
Definition runtime.h:300
dt_drawlayer_runtime_manager_t manager
Definition runtime.h:301
struct dt_develop_t * dev
Definition imageop.h:311
dt_iop_params_t * params
Definition imageop.h:333
int width
Definition format.h:50
int height
Definition format.h:50
void dt_drawlayer_worker_get_snapshot(const dt_drawlayer_worker_t *worker, dt_drawlayer_worker_snapshot_t *snapshot)
Return a thread-safe worker snapshot for runtime scheduling.
Definition worker.c:1737
void dt_drawlayer_worker_stop(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Stop realtime and full-resolution worker threads.
Definition worker.c:1732
gboolean dt_drawlayer_worker_ensure_running(dt_iop_module_t *self, dt_drawlayer_worker_t *rt)
Ensure realtime/backend worker threads are started.
Definition worker.c:1727
gboolean dt_drawlayer_worker_enqueue_stroke_end(dt_drawlayer_worker_t *worker, const dt_drawlayer_paint_raw_input_t *input)
Public FIFO enqueue for stroke-end event.
Definition worker.c:1824
void dt_drawlayer_worker_request_commit(dt_drawlayer_worker_t *worker)
Public commit request helper.
Definition worker.c:1753
gboolean dt_drawlayer_worker_enqueue_input(dt_drawlayer_worker_t *worker, const dt_drawlayer_paint_raw_input_t *input)
Public FIFO enqueue for one raw input event.
Definition worker.c:1817
@ DT_DRAWLAYER_WORKER_STATE_STOPPED
Definition worker.h:35
@ DT_DRAWLAYER_WORKER_STATE_BUSY
Definition worker.h:37
@ DT_DRAWLAYER_WORKER_STATE_PAUSED
Definition worker.h:39
@ DT_DRAWLAYER_WORKER_STATE_PAUSING
Definition worker.h:38