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
20#include "control/control.h"
22#include "develop/develop.h"
23
24#include <string.h>
25
36
43
55
60
62{
63 return state ? state->priv : NULL;
64}
65
67 const gboolean resident, const gboolean valid, const gboolean dirty)
68{
70 if(IS_NULL_PTR(priv) || buffer >= DT_DRAWLAYER_RUNTIME_BUFFER_COUNT) return;
71 priv->buffers[buffer].resident = resident;
72 priv->buffers[buffer].valid = valid;
73 priv->buffers[buffer].dirty = dirty;
74}
75
77{
78 if(IS_NULL_PTR(state)) return;
79 memset(state, 0, sizeof(*state));
80 state->priv = g_malloc0(sizeof(*state->priv));
81 if(state->priv) dt_pthread_mutex_init(&state->priv->mutex, NULL);
82}
83
85{
86 if(IS_NULL_PTR(state)) return;
87 if(state->priv)
88 {
89 dt_pthread_mutex_destroy(&state->priv->mutex);
90 dt_free(state->priv);
91 }
92 memset(state, 0, sizeof(*state));
93}
94
98 const gboolean write_lock,
99 const gboolean acquire)
100{
102 if(IS_NULL_PTR(priv) || buffer >= DT_DRAWLAYER_RUNTIME_BUFFER_COUNT) return;
104 dt_drawlayer_runtime_buffer_state_t *entry = &priv->buffers[buffer];
105
106 if(write_lock)
107 {
108 entry->write_locked = acquire;
109 entry->writer = acquire ? actor : DT_DRAWLAYER_RUNTIME_ACTOR_NONE;
110 }
111 else if(acquire)
112 {
113 entry->read_locks++;
114 entry->last_reader = actor;
115 }
116 else if(entry->read_locks > 0)
117 {
118 entry->read_locks--;
120 }
122}
123
134
137 const gboolean active,
138 const gboolean waiting,
139 const guint queued)
140{
142 if(IS_NULL_PTR(priv) || actor <= DT_DRAWLAYER_RUNTIME_ACTOR_NONE || actor >= DT_DRAWLAYER_RUNTIME_ACTOR_COUNT) return;
144 priv->threads[actor].active = active;
145 priv->threads[actor].waiting = waiting;
146 priv->threads[actor].queued = queued;
148}
149
151 const dt_drawlayer_worker_snapshot_t *worker_snapshot,
153{
154 if(inputs) *inputs = (dt_drawlayer_runtime_inputs_t){ 0 };
155 if(IS_NULL_PTR(runtime) || IS_NULL_PTR(inputs)) return;
156
157 const dt_drawlayer_runtime_request_t *const request = &runtime->runtime;
158 dt_iop_module_t *const self = request->self;
159 dt_iop_drawlayer_gui_data_t *const g = request->gui;
160 dt_drawlayer_process_state_t *const process = request->process_state ? request->process_state : (g ? &g->process : NULL);
161 const dt_iop_drawlayer_params_t *const runtime_params
162 = request->runtime_params ? request->runtime_params : (const dt_iop_drawlayer_params_t *)self->params;
163
165 .session = g ? &g->session : NULL,
166 .process = process,
167 .stroke = g ? &g->stroke : NULL,
168 .worker = worker_snapshot,
169 .base_patch = NULL,
170 .base_patch_valid = FALSE,
171 .base_patch_dirty = FALSE,
172 .painting_active = g && g->manager.painting_active,
173 .gui_attached = self && self->dev && self->dev->gui_attached && g,
174 .module_focused = self && self->dev && self->dev->gui_module == self,
175 .display_pipe = request->display_pipe,
176 .have_layer_selection = runtime_params && runtime_params->layer_name[0] != '\0',
177 .selected_layer_name = runtime_params ? runtime_params->layer_name : NULL,
178 .selected_layer_order = runtime_params ? runtime_params->layer_order : -1,
179 .have_valid_output_roi = request->roi_out && request->roi_out->width > 0 && request->roi_out->height > 0,
180 .use_opencl = request->use_opencl,
181 .view_changed = g && self && self->dev
182 && (fabsf(g->session.last_view_x - self->dev->roi.x) > 1e-6f
183 || fabsf(g->session.last_view_y - self->dev->roi.y) > 1e-6f
184 || fabsf(g->session.last_view_scale - self->dev->roi.scaling) > 1e-6f),
185 .padding_changed = g && self && fabsf(g->session.live_padding - dt_drawlayer_current_live_padding(self)) > 1e-6f,
186 };
187}
188
190 const dt_drawlayer_runtime_context_t *context,
192 dt_drawlayer_worker_snapshot_t *worker_snapshot)
193{
194 if(inputs) *inputs = (dt_drawlayer_runtime_inputs_t){ 0 };
195 if(worker_snapshot) *worker_snapshot = (dt_drawlayer_worker_snapshot_t){ 0 };
196 if(!IS_NULL_PTR(request) && request->inputs)
197 {
198 if(!IS_NULL_PTR(inputs)) *inputs = *request->inputs;
199 return;
200 }
201 if(!IS_NULL_PTR(context) && context->runtime.gui && context->runtime.gui->stroke.worker && !IS_NULL_PTR(worker_snapshot))
202 dt_drawlayer_worker_get_snapshot(context->runtime.gui->stroke.worker, worker_snapshot);
203 _fill_runtime_inputs(context, worker_snapshot, inputs);
204}
205
207 const dt_drawlayer_runtime_inputs_t *inputs)
208{
210 const dt_drawlayer_session_state_t *session = inputs ? inputs->session : NULL;
211 const dt_drawlayer_process_state_t *process = inputs ? inputs->process : NULL;
212 const dt_drawlayer_worker_snapshot_t *worker = inputs ? inputs->worker : NULL;
213 const dt_drawlayer_cache_patch_t *base_patch = inputs ? inputs->base_patch : NULL;
214
215 if(IS_NULL_PTR(priv)) return;
216 state->painting_active = inputs && inputs->painting_active;
217 state->background_job_running = session && session->background_job_running;
218
219 if(!IS_NULL_PTR(process))
220 {
221 priv->layer_cache_valid = process->cache_valid;
223 process->cache_valid, process->cache_dirty);
225 !IS_NULL_PTR(process->stroke_mask.pixels), FALSE);
226 }
227 else if(!IS_NULL_PTR(base_patch))
228 {
229 priv->layer_cache_valid = inputs->base_patch_valid;
231 inputs->base_patch_valid, inputs->base_patch_dirty);
232 }
233
234 if(!IS_NULL_PTR(worker))
235 {
236 const gboolean backend_started = worker->backend_state != DT_DRAWLAYER_WORKER_STATE_STOPPED;
237 const gboolean backend_busy = worker->backend_state == DT_DRAWLAYER_WORKER_STATE_BUSY;
238 const gboolean backend_waiting = (worker->backend_state == DT_DRAWLAYER_WORKER_STATE_PAUSING
240 const gboolean backend_active = backend_started
241 && (backend_busy || worker->backend_queue_count > 0
242 || worker->commit_pending || state->painting_active);
246 }
247}
248
251 const dt_drawlayer_runtime_inputs_t *inputs)
252{
254 if(IS_NULL_PTR(state) || IS_NULL_PTR(request)) return;
255 if(IS_NULL_PTR(priv)) return;
256
257 priv->last_event = request->event;
258 priv->last_raw_input_kind = request->raw_input_kind;
259
260 switch(request->event)
261 {
263 priv->gui_focused = TRUE;
266 break;
267
269 priv->gui_focused = FALSE;
272 break;
273
277 break;
278
287 break;
288
291 = priv->gui_focused && inputs && inputs->gui_attached;
293 break;
294
298 break;
299
303 break;
304
308 break;
309
313 break;
314
317 priv->sidecar_io_active = TRUE;
320 break;
321
324 priv->sidecar_io_active = FALSE;
327 break;
328
332 break;
333
336 = priv->gui_focused && inputs && inputs->gui_attached;
338 break;
339
341 default:
342 break;
343 }
344
345 const gboolean painting_before = state->painting_active;
347 {
349 state->painting_active = TRUE;
351 state->painting_active = FALSE;
352 }
356 {
357 state->painting_active = FALSE;
358 }
359 if(painting_before != state->painting_active)
360 dt_print(DT_DEBUG_PERF, "[drawlayer] painting_active %d->%d by event=%d raw_kind=%d\n",
361 painting_before, state->painting_active, request->event, request->raw_input_kind);
362}
363
366 const dt_drawlayer_runtime_inputs_t *inputs)
367{
369 if(IS_NULL_PTR(state)) return;
370 if(IS_NULL_PTR(priv)) return;
371
372 gboolean realtime_active = priv->gui_focused && inputs && inputs->gui_attached
373 && state->painting_active;
374
375 if(!IS_NULL_PTR(request))
376 {
377 switch(request->event)
378 {
383 realtime_active = FALSE;
384 break;
385
387 // Realtime mode tracks painting_active only (set by _apply_runtime_event on STROKE_BEGIN/END,
388 // which runs just before this). A SAMPLE raw-input also fires on plain hover (cursor tracking)
389 // while NOT painting; forcing realtime on there toggled it on/off against every pipe-finished,
390 // and each flip paid a full resync_history_main (~44ms). Fall through to the base computation so
391 // hover never enters realtime and only an actual stroke does.
392 break;
393
410 default:
411 break;
412 }
413 }
414
415 state->realtime_active = realtime_active;
416}
417
438
441 const dt_drawlayer_runtime_host_t *host,
443
446 const dt_drawlayer_runtime_host_t *host,
447 const dt_drawlayer_runtime_commit_mode_t commit_mode,
449{
450 if(commit_mode == DT_DRAWLAYER_RUNTIME_COMMIT_NONE) return TRUE;
451 const dt_drawlayer_runtime_context_t *const context
452 = host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL;
453 if(IS_NULL_PTR(context) || !context->runtime.self || !context->runtime.gui) return FALSE;
454
457 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
458 .inputs = request ? request->inputs : NULL,
459 };
460 _update_manager_information(state, &begin, host, NULL);
463
466 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
467 .inputs = request ? request->inputs : NULL,
468 };
469 _update_manager_information(state, &end, host, NULL);
471 return TRUE;
472}
473
476{
477 const dt_drawlayer_runtime_context_t *const context
478 = host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL;
479 (void)result;
480 if(IS_NULL_PTR(context) || !context->runtime.self) return FALSE;
483}
484
488
491 const dt_drawlayer_runtime_inputs_t *inputs,
493{
495 if(schedule)
499 };
500 const dt_drawlayer_process_state_t *process = inputs ? inputs->process : NULL;
501 const dt_drawlayer_stroke_state_t *stroke = inputs ? inputs->stroke : NULL;
502 if(IS_NULL_PTR(schedule) || IS_NULL_PTR(inputs) || IS_NULL_PTR(request) || IS_NULL_PTR(priv)) return;
503
504 const gboolean layer_selection_changed
505 = inputs->have_layer_selection && process
506 && (!process->cache_valid || g_strcmp0(process->cache_layer_name,
507 inputs->selected_layer_name ? inputs->selected_layer_name : "")
508 || (process->cache_layer_order >= 0 && inputs->selected_layer_order >= 0
509 && process->cache_layer_order != inputs->selected_layer_order));
510
512
513 const gboolean backend_busy = priv->threads[DT_DRAWLAYER_RUNTIME_ACTOR_RASTER_BACKEND].active;
514 const gboolean have_pending_stroke_work
515 = (state->painting_active || (stroke && (stroke->finish_commit_pending || stroke->stroke_sample_count > 0)))
516 || backend_busy;
517 const gboolean have_pending_gui_stroke_work
518 = state->painting_active || (stroke && stroke->stroke_sample_count > 0);
519 const gboolean have_pending_cache_writes = process && process->cache_dirty;
520
521 switch(request->event)
522 {
524 schedule->sync_realtime_mode = TRUE;
525 schedule->ensure_worker_running = inputs->module_focused;
526 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
527 break;
528
530 schedule->sync_realtime_mode = TRUE;
531 schedule->feedback = schedule->rasterization_busy
534 schedule->commit_mode = have_pending_stroke_work
537 schedule->flush_sidecar = have_pending_cache_writes && process && process->cache_valid;
538 schedule->stop_worker = TRUE;
539 break;
540
542 schedule->set_pointer_state = TRUE;
543 schedule->pointer_valid = TRUE;
544 schedule->pointer_hide_cursor = TRUE;
545 break;
546
548 schedule->sync_realtime_mode = TRUE;
549 schedule->set_pointer_state = TRUE;
550 schedule->pointer_valid = FALSE;
551 schedule->pointer_hide_cursor = FALSE;
552 schedule->queue_redraw_center = TRUE;
553 break;
554
556 schedule->commit_mode = have_pending_gui_stroke_work ? DT_DRAWLAYER_RUNTIME_COMMIT_QUIET
558 schedule->sync_widget_cache = TRUE;
559 schedule->queue_redraw_center = TRUE;
560 break;
561
563 schedule->commit_mode = (request->flush_pending && have_pending_gui_stroke_work)
566 schedule->invalidate_layer_cache = layer_selection_changed;
567 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
568 schedule->ensure_worker_running = inputs->module_focused && inputs->have_layer_selection;
569 break;
570
572 schedule->sync_realtime_mode = TRUE;
573 schedule->commit_mode = have_pending_stroke_work
576 schedule->flush_sidecar = process && process->cache_valid;
577 schedule->stop_worker = TRUE;
578 schedule->invalidate_layer_cache = TRUE;
579 schedule->refresh_gui = TRUE;
580 schedule->sync_widget_cache = TRUE;
581 schedule->ensure_worker_running = inputs->module_focused;
582 break;
583
585 schedule->invalidate_layer_cache = layer_selection_changed;
586 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
587 schedule->ensure_worker_running = inputs->module_focused && inputs->have_layer_selection;
588 break;
589
591 schedule->sync_widget_cache = (inputs->view_changed || inputs->padding_changed)
592 && !state->painting_active && !schedule->rasterization_busy;
593 break;
594
596 schedule->sync_realtime_mode = TRUE;
597 schedule->request_commit = TRUE;
598 break;
599
601 switch(request->raw_input_kind)
602 {
604 schedule->sync_realtime_mode = TRUE;
605 /* A new GUI stroke must first finish any previous stroke that was
606 * still draining/committing. Use the pre-event GUI state from
607 * `inputs`, not the post-event manager state, because `_apply_runtime_event()`
608 * already flipped `state->painting_active` to TRUE for the new stroke. */
609 schedule->commit_mode = (!inputs->painting_active
610 && ((stroke && (stroke->finish_commit_pending || stroke->stroke_sample_count > 0))
611 || backend_busy))
614 schedule->sync_widget_cache = TRUE;
615 schedule->ensure_worker_running = TRUE;
616 schedule->queue_raw_input = TRUE;
617 break;
618
620 schedule->sync_realtime_mode = TRUE;
621 schedule->ensure_worker_running = state->painting_active;
622 schedule->queue_raw_input = state->painting_active;
623 break;
624
626 schedule->sync_realtime_mode = FALSE;
627 schedule->ensure_worker_running = TRUE;
628 schedule->request_commit = TRUE;
629 schedule->queue_raw_input = TRUE;
630 break;
631
633 default:
634 schedule->sync_realtime_mode = TRUE;
635 break;
636 }
637 break;
638
640 schedule->ensure_layer_cache = inputs->display_pipe && inputs->have_layer_selection
641 && !priv->layer_cache_valid;
642 break;
643
645 schedule->ensure_layer_cache = inputs->display_pipe && inputs->have_layer_selection
646 && !priv->layer_cache_valid;
647 break;
648
658 default:
659 break;
660 }
661}
662
665 const dt_drawlayer_runtime_host_t *host,
667{
668 if(schedule) *schedule = (dt_drawlayer_runtime_schedule_t){ 0 };
669 if(IS_NULL_PTR(state)) return;
670
671 dt_drawlayer_runtime_inputs_t inputs = { 0 };
672 dt_drawlayer_worker_snapshot_t worker_snapshot = { 0 };
673 _collect_runtime_inputs(request, host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL,
674 &inputs, &worker_snapshot);
675
677 if(IS_NULL_PTR(priv)) return;
678 dt_pthread_mutex_lock(&priv->mutex);
680 if(request) _apply_runtime_event(state, request, &inputs);
681 _update_realtime_state(state, request, &inputs);
682 _build_runtime_schedule(state, request, &inputs, schedule);
683 dt_pthread_mutex_unlock(&priv->mutex);
684}
685
688 const dt_drawlayer_runtime_host_t *host)
689{
691 .ok = TRUE,
692 .raw_input_ok = TRUE,
693 };
694 if(IS_NULL_PTR(state) || IS_NULL_PTR(request) || IS_NULL_PTR(host)) return result;
695 const dt_drawlayer_runtime_context_t *const context
697 if(IS_NULL_PTR(context)) return result;
698
699 dt_iop_module_t *const self = context->runtime.self;
700 dt_iop_drawlayer_gui_data_t *const g = context->runtime.gui;
701
702 dt_drawlayer_runtime_schedule_t schedule = { 0 };
703 _update_manager_information(state, request, host, &schedule);
704
705 if(schedule.sync_realtime_mode && self && g)
706 dt_drawlayer_set_pipeline_realtime_mode(self, g->manager.realtime_active);
707
708 switch(request->event)
709 {
711 if(schedule.ensure_worker_running && self && g
712 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
713 {
714 dt_control_log(_("failed to start drawing worker"));
715 result.ok = FALSE;
716 }
717 if(schedule.sync_widget_cache && result.ok
718 && !_perform_runtime_widget_cache_sync(host, &result))
719 result.ok = FALSE;
720 break;
721
724 if(schedule.set_pointer_state && g)
725 {
726 g->session.pointer_valid = schedule.pointer_valid;
728 }
730 break;
731
735 if(result.ok
736 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
737 result.ok = FALSE;
738 if(schedule.invalidate_layer_cache && g)
739 {
741 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
742 g->process.cache_valid = FALSE;
743 g->process.cache_dirty = FALSE;
744 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
745 g->process.cache_imgid = -1;
746 g->process.cache_layer_name[0] = '\0';
747 g->process.cache_layer_order = -1;
749 }
750 if(result.ok && schedule.sync_widget_cache
751 && !_perform_runtime_widget_cache_sync(host, &result))
752 result.ok = FALSE;
753 if(result.ok && schedule.ensure_worker_running && self && g
754 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
755 {
756 dt_control_log(_("failed to start drawing worker"));
757 result.ok = FALSE;
758 }
760 break;
761
763 if(schedule.sync_widget_cache && !_perform_runtime_widget_cache_sync(host, &result)) result.ok = FALSE;
764 break;
765
768 if(schedule.request_commit && g) dt_drawlayer_worker_request_commit(g->stroke.worker);
769 break;
770
773 if(result.ok
774 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
775 result.ok = FALSE;
776 if(result.ok && schedule.feedback != DT_DRAWLAYER_RUNTIME_FEEDBACK_NONE && g)
778 if(schedule.flush_sidecar)
779 {
782 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
783 .inputs = request->inputs,
784 };
785 _update_manager_information(state, &begin, host, NULL);
786 if(self && !dt_drawlayer_flush_layer_cache(self))
787 {
788 dt_control_log(_("failed to write drawing layer sidecar"));
789 result.ok = FALSE;
790 }
793 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
794 .inputs = request->inputs,
795 };
796 _update_manager_information(state, &end, host, NULL);
797 }
798 if(schedule.stop_worker && self && g) dt_drawlayer_worker_stop(self, g->stroke.worker);
799 if(schedule.invalidate_layer_cache && g)
800 {
802 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
803 g->process.cache_valid = FALSE;
804 g->process.cache_dirty = FALSE;
805 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
807 }
808 if(schedule.refresh_gui && self) gui_update(self);
809 if(schedule.sync_widget_cache && result.ok
810 && !_perform_runtime_widget_cache_sync(host, &result))
811 result.ok = FALSE;
812 if(schedule.ensure_worker_running && self && g
813 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
814 {
815 dt_control_log(_("failed to start drawing worker"));
816 result.ok = FALSE;
817 }
818 break;
819
822 {
823 if(result.ok
824 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
825 result.ok = FALSE;
826 if(result.ok && schedule.sync_widget_cache
827 && !_perform_runtime_widget_cache_sync(host, &result))
828 result.ok = FALSE;
829 if(result.ok && schedule.ensure_worker_running && self && g)
830 {
831 if(!dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
832 {
833 dt_control_log(_("failed to start drawing worker"));
834 result.ok = FALSE;
835 }
836 }
837 if(result.ok && self) dt_drawlayer_begin_gui_stroke_capture(self, context->raw_input);
838 }
841
842 if(result.ok && schedule.ensure_worker_running && self && g
844 {
845 if(!dt_drawlayer_worker_ensure_running(self, g->stroke.worker)
847 {
848 dt_control_log(_("failed to start drawing worker"));
849 result.ok = FALSE;
850 }
851 }
852
853 if(schedule.request_commit && g) dt_drawlayer_worker_request_commit(g->stroke.worker);
854
855 if(schedule.queue_raw_input && g)
856 {
857 gboolean ok = TRUE;
858 if(IS_NULL_PTR(context->raw_input))
859 ok = FALSE;
861 ok = dt_drawlayer_worker_enqueue_stroke_end(g->stroke.worker, context->raw_input);
864 ok = dt_drawlayer_worker_enqueue_input(g->stroke.worker, context->raw_input);
865 result.raw_input_ok = ok;
866 }
867 break;
868
871 if(schedule.ensure_layer_cache)
872 {
875 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
876 .inputs = request->inputs,
877 };
878 _update_manager_information(state, &begin, host, NULL);
879 if(self && !dt_drawlayer_ensure_layer_cache(self)) result.ok = FALSE;
882 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
883 .inputs = request->inputs,
884 };
885 _update_manager_information(state, &end, host, NULL);
886 }
887 break;
888
898 default:
899 break;
900 }
901
902 if(request->release.source)
904
905 _update_manager_information(state, request->inputs ? request : NULL, host, NULL);
906 if(schedule.sync_realtime_mode && self && g)
907 dt_drawlayer_set_pipeline_realtime_mode(self, g->manager.realtime_active);
908
909 return result;
910}
911
913 dt_drawlayer_process_state_t *headless_process,
915 dt_drawlayer_process_state_t *gui_process,
916 const gboolean display_pipe,
917 dt_drawlayer_runtime_manager_t **runtime_manager,
918 dt_drawlayer_process_state_t **runtime_process,
919 gboolean *runtime_display_pipe)
920{
921 if(!IS_NULL_PTR(runtime_manager)) *runtime_manager = display_pipe ? gui_manager : headless_manager;
922 if(!IS_NULL_PTR(runtime_process)) *runtime_process = display_pipe ? gui_process : headless_process;
923 if(!IS_NULL_PTR(runtime_display_pipe)) *runtime_display_pipe = display_pipe;
924}
925
927{
928 if(IS_NULL_PTR(state)) return;
929 memset(state, 0, sizeof(*state));
930 state->cache_imgid = -1;
931 state->cache_layer_order = -1;
932}
933
935{
936 if(IS_NULL_PTR(state)) return;
937 dt_drawlayer_cache_patch_clear(&state->base_patch, "drawlayer patch");
938 dt_drawlayer_cache_patch_clear(&state->stroke_mask, "drawlayer patch");
939 memset(state, 0, sizeof(*state));
940 state->cache_imgid = -1;
941 state->cache_layer_order = -1;
942}
943
945{
946 if(IS_NULL_PTR(state)) return;
947 if(state->stroke_mask.pixels)
948 memset(state->stroke_mask.pixels, 0, (size_t)state->stroke_mask.width * state->stroke_mask.height * sizeof(float));
949}
950
952{
953 if(IS_NULL_PTR(state)) return;
954 dt_drawlayer_cache_patch_clear(&state->stroke_mask, "drawlayer stroke mask");
955 /* Any state invalidation may relocate/free the output buffer this tracked, so
956 * the realtime partial-composite fast path can no longer trust it. */
957 state->last_composite_valid = FALSE;
958 state->last_composite_dev_out = NULL;
959}
960
964{
965 if(IS_NULL_PTR(source)) return;
966
967 if(state && source->tracked_read_lock)
969 FALSE);
970
971 switch(source->kind)
972 {
975 break;
976
978 default:
979 break;
980 }
981
982 *source = (dt_drawlayer_runtime_source_t){ 0 };
983}
984
986{
987 if(IS_NULL_PTR(state)) return;
988 if(state->cursor_surface)
989 {
990 cairo_surface_destroy(state->cursor_surface);
991 state->cursor_surface = NULL;
992 }
993 state->cursor_surface_size = 0;
994 state->cursor_surface_ppd = 0.0;
995 state->cursor_radius = 0.0f;
996 state->cursor_opacity = 0.0f;
997 state->cursor_hardness = 0.0f;
998 state->cursor_shape = -1;
999 state->cursor_color[0] = state->cursor_color[1] = state->cursor_color[2] = -1.0f;
1000}
__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:3153
void gui_update(struct dt_iop_module_t *self)
Definition ashift.c:5553
#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_log(const char *msg,...)
Definition control.c:761
void dt_control_queue_redraw_center()
request redraw of center window. This redraws the center view within a gdk critical section to preven...
Definition control.c:861
#define dt_control_set_cursor_visible(visible)
Definition control.h:148
float dt_drawlayer_current_live_padding(dt_iop_module_t *self)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1542
@ DT_DEBUG_PERF
Definition darktable.h:719
#define dt_free(ptr)
Definition darktable.h:456
#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:281
gboolean dt_drawlayer_flush_layer_cache(dt_iop_module_t *self)
Definition layers.c:358
void dt_drawlayer_show_runtime_feedback(const dt_iop_drawlayer_gui_data_t *g, const dt_drawlayer_runtime_feedback_t feedback)
Definition drawlayer.c:2687
gboolean dt_drawlayer_sync_widget_cache(dt_iop_module_t *self)
Definition layers.c:468
void dt_drawlayer_begin_gui_stroke_capture(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *first_input)
Definition drawlayer.c:2623
void dt_drawlayer_release_all_base_patch_extra_refs(dt_iop_drawlayer_gui_data_t *g)
Definition drawlayer.c:483
gboolean dt_drawlayer_commit_dabs(dt_iop_module_t *self, gboolean record_history)
Definition drawlayer.c:1742
void dt_drawlayer_set_pipeline_realtime_mode(dt_iop_module_t *self, gboolean state)
Definition layers.c:450
void dt_drawlayer_end_gui_stroke_capture(dt_iop_module_t *self)
Definition drawlayer.c:2646
static int dt_pthread_mutex_unlock(dt_pthread_mutex_t *mutex) RELEASE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:374
static int dt_pthread_mutex_init(dt_pthread_mutex_t *mutex, const pthread_mutexattr_t *mutexattr)
Definition dtpthread.h:359
static int dt_pthread_mutex_destroy(dt_pthread_mutex_t *mutex)
Definition dtpthread.h:379
static int dt_pthread_mutex_lock(dt_pthread_mutex_t *mutex) ACQUIRE(mutex) NO_THREAD_SAFETY_ANALYSIS
Definition dtpthread.h:364
void dt_drawlayer_paint_runtime_state_reset(dt_drawlayer_damaged_rect_t *state)
Reset stroke-damage accumulator to empty/invalid.
Pixelpipe cache for storing intermediate results in the pixelpipe.
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:961
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:912
void dt_drawlayer_runtime_manager_cleanup(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:84
static const dt_drawlayer_runtime_private_t * _runtime_private_const(const dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:61
void dt_drawlayer_runtime_manager_init(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:76
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:686
void dt_drawlayer_process_state_reset_stroke(dt_drawlayer_process_state_t *state)
Definition runtime.c:944
void dt_drawlayer_process_state_init(dt_drawlayer_process_state_t *state)
Definition runtime.c:926
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:444
void dt_drawlayer_ui_cursor_clear(dt_drawlayer_ui_state_t *state)
Definition runtime.c:985
void dt_drawlayer_process_state_cleanup(dt_drawlayer_process_state_t *state)
Definition runtime.c:934
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:95
static gboolean _perform_runtime_widget_cache_sync(const dt_drawlayer_runtime_host_t *host, dt_drawlayer_runtime_result_t *result)
Definition runtime.c:474
static void _sync_runtime_state_from_inputs(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_inputs_t *inputs)
Definition runtime.c:206
static dt_drawlayer_runtime_private_t * _runtime_private(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:56
void dt_drawlayer_runtime_manager_note_sidecar_io(dt_drawlayer_runtime_manager_t *state, const gboolean active)
Definition runtime.c:124
void dt_drawlayer_process_state_invalidate(dt_drawlayer_process_state_t *state)
Definition runtime.c:951
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:364
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:663
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:150
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:66
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:189
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:249
void dt_drawlayer_runtime_manager_note_thread(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_actor_t actor, const gboolean active, const gboolean waiting, const guint queued)
Definition runtime.c:135
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:489
Private runtime state/helpers shared by drawlayer module entrypoints.
dt_drawlayer_runtime_raw_input_kind_t
Definition runtime.h:205
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE
Definition runtime.h:206
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_BEGIN
Definition runtime.h:208
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_END
Definition runtime.h:209
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_SAMPLE
Definition runtime.h:207
@ DT_DRAWLAYER_SOURCE_BASE_PATCH
Definition runtime.h:309
@ DT_DRAWLAYER_SOURCE_NONE
Definition runtime.h:308
dt_drawlayer_runtime_actor_t
Definition runtime.h:161
@ DT_DRAWLAYER_RUNTIME_ACTOR_GUI
Definition runtime.h:163
@ DT_DRAWLAYER_RUNTIME_ACTOR_RASTER_BACKEND
Definition runtime.h:166
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CPU
Definition runtime.h:164
@ DT_DRAWLAYER_RUNTIME_ACTOR_COUNT
Definition runtime.h:168
@ DT_DRAWLAYER_RUNTIME_ACTOR_TIFF_IO
Definition runtime.h:167
@ DT_DRAWLAYER_RUNTIME_ACTOR_NONE
Definition runtime.h:162
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CL
Definition runtime.h:165
dt_drawlayer_runtime_commit_mode_t
Definition runtime.h:213
@ DT_DRAWLAYER_RUNTIME_COMMIT_HISTORY
Definition runtime.h:216
@ DT_DRAWLAYER_RUNTIME_COMMIT_QUIET
Definition runtime.h:215
@ DT_DRAWLAYER_RUNTIME_COMMIT_NONE
Definition runtime.h:214
dt_drawlayer_runtime_buffer_t
Definition runtime.h:172
@ DT_DRAWLAYER_RUNTIME_BUFFER_COUNT
Definition runtime.h:175
@ DT_DRAWLAYER_RUNTIME_BUFFER_BASE_PATCH
Definition runtime.h:173
@ DT_DRAWLAYER_RUNTIME_BUFFER_STROKE_MASK
Definition runtime.h:174
dt_drawlayer_runtime_event_t
Definition runtime.h:179
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_LOAD_END
Definition runtime.h:197
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_GAIN
Definition runtime.h:181
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_LOAD_BEGIN
Definition runtime.h:196
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC
Definition runtime.h:188
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_AFTER
Definition runtime.h:193
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SCROLL
Definition runtime.h:185
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_BEFORE
Definition runtime.h:194
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_PIPE_FINISHED
Definition runtime.h:189
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_AFTER
Definition runtime.h:195
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_CHANGE_IMAGE
Definition runtime.h:187
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RAW_INPUT
Definition runtime.h:191
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_BEFORE
Definition runtime.h:192
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_SAVE_END
Definition runtime.h:199
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_LEAVE
Definition runtime.h:184
@ DT_DRAWLAYER_RUNTIME_EVENT_COMMIT_BEGIN
Definition runtime.h:200
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT
Definition runtime.h:190
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_ENTER
Definition runtime.h:183
@ DT_DRAWLAYER_RUNTIME_EVENT_COMMIT_END
Definition runtime.h:201
@ DT_DRAWLAYER_RUNTIME_EVENT_NONE
Definition runtime.h:180
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_SAVE_BEGIN
Definition runtime.h:198
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_LOSS
Definition runtime.h:182
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SYNC_TEMP_BUFFERS
Definition runtime.h:186
const float uint32_t state[4]
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.
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:126
int32_t gui_attached
Definition develop.h:162
struct dt_iop_module_t * gui_module
Definition develop.h:165
float scaling
Definition develop.h:193
struct dt_develop_t::@17 roi
Generic float RGBA patch stored either in malloc memory or pixel cache.
dt_drawlayer_runtime_actor_t writer
Definition runtime.c:34
dt_drawlayer_runtime_actor_t last_reader
Definition runtime.c:32
const dt_drawlayer_paint_raw_input_t * raw_input
Definition runtime.h:298
dt_drawlayer_runtime_request_t runtime
Definition runtime.h:297
const dt_drawlayer_stroke_state_t * stroke
Definition runtime.h:239
const dt_drawlayer_session_state_t * session
Definition runtime.h:237
const char * selected_layer_name
Definition runtime.h:249
const dt_drawlayer_worker_snapshot_t * worker
Definition runtime.h:240
const dt_drawlayer_cache_patch_t * base_patch
Definition runtime.h:241
const dt_drawlayer_process_state_t * process
Definition runtime.h:238
dt_drawlayer_runtime_buffer_state_t buffers[DT_DRAWLAYER_RUNTIME_BUFFER_COUNT]
Definition runtime.c:47
dt_drawlayer_runtime_event_t last_event
Definition runtime.c:52
dt_drawlayer_runtime_thread_state_t threads[DT_DRAWLAYER_RUNTIME_ACTOR_COUNT]
Definition runtime.c:48
dt_pthread_mutex_t mutex
Definition runtime.c:46
dt_drawlayer_runtime_raw_input_kind_t last_raw_input_kind
Definition runtime.c:53
dt_drawlayer_runtime_source_t * source
Definition runtime.h:331
dt_drawlayer_process_state_t * process
Definition runtime.h:330
const dt_iop_drawlayer_params_t * runtime_params
Definition runtime.h:285
dt_iop_module_t * self
Definition runtime.h:282
dt_iop_drawlayer_gui_data_t * gui
Definition runtime.h:286
dt_drawlayer_process_state_t * process_state
Definition runtime.h:288
const dt_iop_roi_t * roi_out
Definition runtime.h:291
dt_drawlayer_runtime_commit_mode_t commit_mode
Definition runtime.c:420
dt_drawlayer_runtime_feedback_t feedback
Definition runtime.c:422
dt_drawlayer_runtime_buffer_t tracked_buffer
Definition runtime.h:323
dt_drawlayer_runtime_source_kind_t kind
Definition runtime.h:314
dt_drawlayer_runtime_actor_t tracked_actor
Definition runtime.h:324
const dt_drawlayer_runtime_inputs_t * inputs
Definition runtime.h:338
dt_drawlayer_runtime_event_t event
Definition runtime.h:336
dt_drawlayer_runtime_release_t release
Definition runtime.h:340
dt_drawlayer_runtime_raw_input_kind_t raw_input_kind
Definition runtime.h:337
dt_drawlayer_worker_t * worker
Definition runtime.h:74
dt_drawlayer_worker_state_t backend_state
Definition worker.h:40
dt_drawlayer_stroke_state_t stroke
Definition runtime.h:274
dt_drawlayer_runtime_manager_t manager
Definition runtime.h:275
struct dt_develop_t * dev
Definition imageop.h:296
dt_iop_params_t * params
Definition imageop.h:307
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:1566
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:1561
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:1556
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:1661
void dt_drawlayer_worker_request_commit(dt_drawlayer_worker_t *worker)
Public commit request helper.
Definition worker.c:1582
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:1654
@ DT_DRAWLAYER_WORKER_STATE_STOPPED
Definition worker.h:32
@ DT_DRAWLAYER_WORKER_STATE_BUSY
Definition worker.h:34
@ DT_DRAWLAYER_WORKER_STATE_PAUSED
Definition worker.h:36
@ DT_DRAWLAYER_WORKER_STATE_PAUSING
Definition worker.h:35