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
135
138 const gboolean active,
139 const gboolean waiting,
140 const guint queued)
141{
143 if(IS_NULL_PTR(priv) || actor <= DT_DRAWLAYER_RUNTIME_ACTOR_NONE || actor >= DT_DRAWLAYER_RUNTIME_ACTOR_COUNT) return;
145 priv->threads[actor].active = active;
146 priv->threads[actor].waiting = waiting;
147 priv->threads[actor].queued = queued;
149}
150
152 const dt_drawlayer_worker_snapshot_t *worker_snapshot,
154{
155 if(inputs) *inputs = (dt_drawlayer_runtime_inputs_t){ 0 };
156 if(IS_NULL_PTR(runtime) || IS_NULL_PTR(inputs)) return;
157
158 const dt_drawlayer_runtime_request_t *const request = &runtime->runtime;
159 dt_iop_module_t *const self = request->self;
160 dt_iop_drawlayer_gui_data_t *const g = request->gui;
161 dt_drawlayer_process_state_t *const process = request->process_state ? request->process_state : (g ? &g->process : NULL);
162 const dt_iop_drawlayer_params_t *const runtime_params
163 = request->runtime_params ? request->runtime_params : (const dt_iop_drawlayer_params_t *)self->params;
164
166 .session = g ? &g->session : NULL,
167 .process = process,
168 .stroke = g ? &g->stroke : NULL,
169 .worker = worker_snapshot,
170 .base_patch = NULL,
171 .base_patch_valid = FALSE,
172 .base_patch_dirty = FALSE,
173 .painting_active = g && g->manager.painting_active,
174 .gui_attached = self && self->dev && self->dev->gui_attached && g,
175 .module_focused = self && self->dev && self->dev->gui_module == self,
176 .display_pipe = request->display_pipe,
177 .have_layer_selection = runtime_params && runtime_params->layer_name[0] != '\0',
178 .selected_layer_name = runtime_params ? runtime_params->layer_name : NULL,
179 .selected_layer_order = runtime_params ? runtime_params->layer_order : -1,
180 .have_valid_output_roi = request->roi_out && request->roi_out->width > 0 && request->roi_out->height > 0,
181 .use_opencl = request->use_opencl,
182 .view_changed = g && self && self->dev
183 && (fabsf(g->session.last_view_x - dt_dev_viewport_center_x(self->dev)) > 1e-6f
184 || fabsf(g->session.last_view_y - dt_dev_viewport_center_y(self->dev)) > 1e-6f
185 || fabsf(g->session.last_view_scale - dt_dev_viewport_scaling(self->dev)) > 1e-6f),
186 .padding_changed = g && self && fabsf(g->session.live_padding - dt_drawlayer_current_live_padding(self)) > 1e-6f,
187 };
188}
189
191 const dt_drawlayer_runtime_context_t *context,
193 dt_drawlayer_worker_snapshot_t *worker_snapshot)
194{
195 if(inputs) *inputs = (dt_drawlayer_runtime_inputs_t){ 0 };
196 if(worker_snapshot) *worker_snapshot = (dt_drawlayer_worker_snapshot_t){ 0 };
197 if(!IS_NULL_PTR(request) && request->inputs)
198 {
199 if(!IS_NULL_PTR(inputs)) *inputs = *request->inputs;
200 return;
201 }
202 if(!IS_NULL_PTR(context) && context->runtime.gui && context->runtime.gui->stroke.worker && !IS_NULL_PTR(worker_snapshot))
203 dt_drawlayer_worker_get_snapshot(context->runtime.gui->stroke.worker, worker_snapshot);
204 _fill_runtime_inputs(context, worker_snapshot, inputs);
205}
206
208 const dt_drawlayer_runtime_inputs_t *inputs)
209{
211 const dt_drawlayer_session_state_t *session = inputs ? inputs->session : NULL;
212 const dt_drawlayer_process_state_t *process = inputs ? inputs->process : NULL;
213 const dt_drawlayer_worker_snapshot_t *worker = inputs ? inputs->worker : NULL;
214 const dt_drawlayer_cache_patch_t *base_patch = inputs ? inputs->base_patch : NULL;
215
216 if(IS_NULL_PTR(priv)) return;
217 state->painting_active = inputs && inputs->painting_active;
218 state->background_job_running = session && session->background_job_running;
219
220 if(!IS_NULL_PTR(process))
221 {
222 priv->layer_cache_valid = process->cache_valid;
224 process->cache_valid, process->cache_dirty);
226 !IS_NULL_PTR(process->stroke_mask.pixels), FALSE);
227 }
228 else if(!IS_NULL_PTR(base_patch))
229 {
230 priv->layer_cache_valid = inputs->base_patch_valid;
232 inputs->base_patch_valid, inputs->base_patch_dirty);
233 }
234
235 if(!IS_NULL_PTR(worker))
236 {
237 const gboolean backend_started = worker->backend_state != DT_DRAWLAYER_WORKER_STATE_STOPPED;
238 const gboolean backend_busy = worker->backend_state == DT_DRAWLAYER_WORKER_STATE_BUSY;
239 const gboolean backend_waiting = (worker->backend_state == DT_DRAWLAYER_WORKER_STATE_PAUSING
241 const gboolean backend_active = backend_started
242 && (backend_busy || worker->backend_queue_count > 0
243 || worker->commit_pending || state->painting_active);
247 }
248}
249
252 const dt_drawlayer_runtime_inputs_t *inputs)
253{
255 if(IS_NULL_PTR(state) || IS_NULL_PTR(request)) return;
256 if(IS_NULL_PTR(priv)) return;
257
258 priv->last_event = request->event;
259 priv->last_raw_input_kind = request->raw_input_kind;
260
261 switch(request->event)
262 {
264 priv->gui_focused = TRUE;
267 break;
268
270 priv->gui_focused = FALSE;
273 break;
274
278 break;
279
288 break;
289
292 = priv->gui_focused && inputs && inputs->gui_attached;
294 break;
295
299 break;
300
304 break;
305
309 break;
310
314 break;
315
318 priv->sidecar_io_active = TRUE;
321 break;
322
325 priv->sidecar_io_active = FALSE;
328 break;
329
333 break;
334
337 = priv->gui_focused && inputs && inputs->gui_attached;
339 break;
340
342 default:
343 break;
344 }
345
346 const gboolean painting_before = state->painting_active;
348 {
350 state->painting_active = TRUE;
352 state->painting_active = FALSE;
353 }
357 {
358 state->painting_active = FALSE;
359 }
360 if(painting_before != state->painting_active)
361 dt_print(DT_DEBUG_PERF, "[drawlayer] painting_active %d->%d by event=%d raw_kind=%d\n",
362 painting_before, state->painting_active, request->event, request->raw_input_kind);
363}
364
367 const dt_drawlayer_runtime_inputs_t *inputs)
368{
370 if(IS_NULL_PTR(state)) return;
371 if(IS_NULL_PTR(priv)) return;
372
373 gboolean realtime_active = priv->gui_focused && inputs && inputs->gui_attached
374 && state->painting_active;
375
376 if(!IS_NULL_PTR(request))
377 {
378 switch(request->event)
379 {
384 realtime_active = FALSE;
385 break;
386
388 // Realtime mode tracks painting_active only (set by _apply_runtime_event on STROKE_BEGIN/END,
389 // which runs just before this). A SAMPLE raw-input also fires on plain hover (cursor tracking)
390 // while NOT painting; forcing realtime on there toggled it on/off against every pipe-finished,
391 // and each flip paid a full resync_history_main (~44ms). Fall through to the base computation so
392 // hover never enters realtime and only an actual stroke does.
393 break;
394
411 default:
412 break;
413 }
414 }
415
416 state->realtime_active = realtime_active;
417}
418
439
442 const dt_drawlayer_runtime_host_t *host,
444
447 const dt_drawlayer_runtime_host_t *host,
448 const dt_drawlayer_runtime_commit_mode_t commit_mode,
450{
451 if(commit_mode == DT_DRAWLAYER_RUNTIME_COMMIT_NONE) return TRUE;
452 const dt_drawlayer_runtime_context_t *const context
453 = host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL;
454 if(IS_NULL_PTR(context) || !context->runtime.self || !context->runtime.gui) return FALSE;
455
458 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
459 .inputs = request ? request->inputs : NULL,
460 };
461 _update_manager_information(state, &begin, host, NULL);
464
467 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
468 .inputs = request ? request->inputs : NULL,
469 };
470 _update_manager_information(state, &end, host, NULL);
472 return TRUE;
473}
474
477{
478 const dt_drawlayer_runtime_context_t *const context
479 = host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL;
480 (void)result;
481 if(IS_NULL_PTR(context) || !context->runtime.self) return FALSE;
484}
485
489
492 const dt_drawlayer_runtime_inputs_t *inputs,
494{
496 if(schedule)
500 };
501 const dt_drawlayer_process_state_t *process = inputs ? inputs->process : NULL;
502 const dt_drawlayer_stroke_state_t *stroke = inputs ? inputs->stroke : NULL;
503 if(IS_NULL_PTR(schedule) || IS_NULL_PTR(inputs) || IS_NULL_PTR(request) || IS_NULL_PTR(priv)) return;
504
505 const gboolean layer_selection_changed
506 = inputs->have_layer_selection && process
507 && (!process->cache_valid || g_strcmp0(process->cache_layer_name,
508 inputs->selected_layer_name ? inputs->selected_layer_name : "")
509 || (process->cache_layer_order >= 0 && inputs->selected_layer_order >= 0
510 && process->cache_layer_order != inputs->selected_layer_order));
511
513
514 const gboolean backend_busy = priv->threads[DT_DRAWLAYER_RUNTIME_ACTOR_RASTER_BACKEND].active;
515 const gboolean have_pending_stroke_work
516 = (state->painting_active || (stroke && (stroke->finish_commit_pending || stroke->stroke_sample_count > 0)))
517 || backend_busy;
518 const gboolean have_pending_gui_stroke_work
519 = state->painting_active || (stroke && stroke->stroke_sample_count > 0);
520 const gboolean have_pending_cache_writes = process && process->cache_dirty;
521
522 switch(request->event)
523 {
525 schedule->sync_realtime_mode = TRUE;
526 schedule->ensure_worker_running = inputs->module_focused;
527 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
528 break;
529
531 schedule->sync_realtime_mode = TRUE;
532 schedule->feedback = schedule->rasterization_busy
535 schedule->commit_mode = have_pending_stroke_work
538 schedule->flush_sidecar = have_pending_cache_writes && process && process->cache_valid;
539 schedule->stop_worker = TRUE;
540 break;
541
543 schedule->set_pointer_state = TRUE;
544 schedule->pointer_valid = TRUE;
545 schedule->pointer_hide_cursor = TRUE;
546 break;
547
549 schedule->sync_realtime_mode = TRUE;
550 schedule->set_pointer_state = TRUE;
551 schedule->pointer_valid = FALSE;
552 schedule->pointer_hide_cursor = FALSE;
553 schedule->queue_redraw_center = TRUE;
554 break;
555
557 schedule->commit_mode = have_pending_gui_stroke_work ? DT_DRAWLAYER_RUNTIME_COMMIT_QUIET
559 schedule->sync_widget_cache = TRUE;
560 schedule->queue_redraw_center = TRUE;
561 break;
562
564 schedule->commit_mode = (request->flush_pending && have_pending_gui_stroke_work)
567 schedule->invalidate_layer_cache = layer_selection_changed;
568 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
569 schedule->ensure_worker_running = inputs->module_focused && inputs->have_layer_selection;
570 break;
571
573 schedule->sync_realtime_mode = TRUE;
574 schedule->commit_mode = have_pending_stroke_work
577 schedule->flush_sidecar = process && process->cache_valid;
578 schedule->stop_worker = TRUE;
579 schedule->invalidate_layer_cache = TRUE;
580 schedule->refresh_gui = TRUE;
581 schedule->sync_widget_cache = TRUE;
582 schedule->ensure_worker_running = inputs->module_focused;
583 break;
584
586 schedule->invalidate_layer_cache = layer_selection_changed;
587 schedule->sync_widget_cache = inputs->gui_attached && inputs->have_layer_selection;
588 schedule->ensure_worker_running = inputs->module_focused && inputs->have_layer_selection;
589 break;
590
592 schedule->sync_widget_cache = (inputs->view_changed || inputs->padding_changed)
593 && !state->painting_active && !schedule->rasterization_busy;
594 break;
595
597 schedule->sync_realtime_mode = TRUE;
598 schedule->request_commit = TRUE;
599 break;
600
602 switch(request->raw_input_kind)
603 {
605 schedule->sync_realtime_mode = TRUE;
606 /* A new GUI stroke must first finish any previous stroke that was
607 * still draining/committing. Use the pre-event GUI state from
608 * `inputs`, not the post-event manager state, because `_apply_runtime_event()`
609 * already flipped `state->painting_active` to TRUE for the new stroke. */
610 schedule->commit_mode = (!inputs->painting_active
611 && ((stroke && (stroke->finish_commit_pending || stroke->stroke_sample_count > 0))
612 || backend_busy))
615 schedule->sync_widget_cache = TRUE;
616 schedule->ensure_worker_running = TRUE;
617 schedule->queue_raw_input = TRUE;
618 break;
619
621 schedule->sync_realtime_mode = TRUE;
622 schedule->ensure_worker_running = state->painting_active;
623 schedule->queue_raw_input = state->painting_active;
624 break;
625
627 schedule->sync_realtime_mode = FALSE;
628 schedule->ensure_worker_running = TRUE;
629 schedule->request_commit = TRUE;
630 schedule->queue_raw_input = TRUE;
631 break;
632
634 default:
635 schedule->sync_realtime_mode = TRUE;
636 break;
637 }
638 break;
639
641 schedule->ensure_layer_cache = inputs->display_pipe && inputs->have_layer_selection
642 && !priv->layer_cache_valid;
643 break;
644
646 schedule->ensure_layer_cache = inputs->display_pipe && inputs->have_layer_selection
647 && !priv->layer_cache_valid;
648 break;
649
659 default:
660 break;
661 }
662}
663
666 const dt_drawlayer_runtime_host_t *host,
668{
669 if(schedule) *schedule = (dt_drawlayer_runtime_schedule_t){ 0 };
670 if(IS_NULL_PTR(state)) return;
671
672 dt_drawlayer_runtime_inputs_t inputs = { 0 };
673 dt_drawlayer_worker_snapshot_t worker_snapshot = { 0 };
674 _collect_runtime_inputs(request, host ? (const dt_drawlayer_runtime_context_t *)host->user_data : NULL,
675 &inputs, &worker_snapshot);
676
678 if(IS_NULL_PTR(priv)) return;
679 dt_pthread_mutex_lock(&priv->mutex);
681 if(request) _apply_runtime_event(state, request, &inputs);
682 _update_realtime_state(state, request, &inputs);
683 _build_runtime_schedule(state, request, &inputs, schedule);
684 dt_pthread_mutex_unlock(&priv->mutex);
685}
686
689 const dt_drawlayer_runtime_host_t *host)
690{
692 .ok = TRUE,
693 .raw_input_ok = TRUE,
694 };
695 if(IS_NULL_PTR(state) || IS_NULL_PTR(request) || IS_NULL_PTR(host)) return result;
696 const dt_drawlayer_runtime_context_t *const context
698 if(IS_NULL_PTR(context)) return result;
699
700 dt_iop_module_t *const self = context->runtime.self;
701 dt_iop_drawlayer_gui_data_t *const g = context->runtime.gui;
702
703 dt_drawlayer_runtime_schedule_t schedule = { 0 };
704 _update_manager_information(state, request, host, &schedule);
705
706 if(schedule.sync_realtime_mode && self && g)
707 dt_drawlayer_set_pipeline_realtime_mode(self, g->manager.realtime_active);
708
709 switch(request->event)
710 {
712 if(schedule.ensure_worker_running && self && g
713 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
714 {
715 dt_control_log(_("failed to start drawing worker"));
716 result.ok = FALSE;
717 }
718 if(schedule.sync_widget_cache && result.ok
719 && !_perform_runtime_widget_cache_sync(host, &result))
720 result.ok = FALSE;
721 break;
722
725 if(schedule.set_pointer_state && g)
726 {
727 g->session.pointer_valid = schedule.pointer_valid;
729 }
731 break;
732
736 if(result.ok
737 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
738 result.ok = FALSE;
739 if(schedule.invalidate_layer_cache && g)
740 {
742 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
743 g->process.cache_valid = FALSE;
744 g->process.cache_dirty = FALSE;
745 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
746 g->process.cache_imgid = -1;
747 g->process.cache_layer_name[0] = '\0';
748 g->process.cache_layer_order = -1;
750 }
751 if(result.ok && schedule.sync_widget_cache
752 && !_perform_runtime_widget_cache_sync(host, &result))
753 result.ok = FALSE;
754 if(result.ok && schedule.ensure_worker_running && self && g
755 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
756 {
757 dt_control_log(_("failed to start drawing worker"));
758 result.ok = FALSE;
759 }
761 break;
762
764 if(schedule.sync_widget_cache && !_perform_runtime_widget_cache_sync(host, &result)) result.ok = FALSE;
765 break;
766
769 if(schedule.request_commit && g) dt_drawlayer_worker_request_commit(g->stroke.worker);
770 break;
771
774 if(result.ok
775 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
776 result.ok = FALSE;
777 if(result.ok && schedule.feedback != DT_DRAWLAYER_RUNTIME_FEEDBACK_NONE && g)
779 if(schedule.flush_sidecar)
780 {
783 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
784 .inputs = request->inputs,
785 };
786 _update_manager_information(state, &begin, host, NULL);
787 if(self && !dt_drawlayer_flush_layer_cache(self))
788 {
789 dt_control_log(_("failed to write drawing layer sidecar"));
790 result.ok = FALSE;
791 }
794 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
795 .inputs = request->inputs,
796 };
797 _update_manager_information(state, &end, host, NULL);
798 }
799 if(schedule.stop_worker && self && g) dt_drawlayer_worker_stop(self, g->stroke.worker);
800 if(schedule.invalidate_layer_cache && g)
801 {
803 dt_drawlayer_cache_patch_clear(&g->process.base_patch, "drawlayer patch");
804 g->process.cache_valid = FALSE;
805 g->process.cache_dirty = FALSE;
806 dt_drawlayer_paint_runtime_state_reset(&g->process.cache_dirty_rect);
808 }
809 if(schedule.refresh_gui && self) gui_update(self);
810 if(schedule.sync_widget_cache && result.ok
811 && !_perform_runtime_widget_cache_sync(host, &result))
812 result.ok = FALSE;
813 if(schedule.ensure_worker_running && self && g
814 && !dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
815 {
816 dt_control_log(_("failed to start drawing worker"));
817 result.ok = FALSE;
818 }
819 break;
820
823 {
824 if(result.ok
825 && !_perform_runtime_commit_sequence(state, request, host, schedule.commit_mode, &result))
826 result.ok = FALSE;
827 if(result.ok && schedule.sync_widget_cache
828 && !_perform_runtime_widget_cache_sync(host, &result))
829 result.ok = FALSE;
830 if(result.ok && schedule.ensure_worker_running && self && g)
831 {
832 if(!dt_drawlayer_worker_ensure_running(self, g->stroke.worker))
833 {
834 dt_control_log(_("failed to start drawing worker"));
835 result.ok = FALSE;
836 }
837 }
838 if(result.ok && self) dt_drawlayer_begin_gui_stroke_capture(self, context->raw_input);
839 }
842
843 if(result.ok && schedule.ensure_worker_running && self && g
845 {
846 if(!dt_drawlayer_worker_ensure_running(self, g->stroke.worker)
848 {
849 dt_control_log(_("failed to start drawing worker"));
850 result.ok = FALSE;
851 }
852 }
853
854 if(schedule.request_commit && g) dt_drawlayer_worker_request_commit(g->stroke.worker);
855
856 if(schedule.queue_raw_input && g)
857 {
858 gboolean ok = TRUE;
859 if(IS_NULL_PTR(context->raw_input))
860 ok = FALSE;
862 ok = dt_drawlayer_worker_enqueue_stroke_end(g->stroke.worker, context->raw_input);
865 ok = dt_drawlayer_worker_enqueue_input(g->stroke.worker, context->raw_input);
866 result.raw_input_ok = ok;
867 }
868 break;
869
872 if(schedule.ensure_layer_cache)
873 {
876 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
877 .inputs = request->inputs,
878 };
879 _update_manager_information(state, &begin, host, NULL);
880 if(self && !dt_drawlayer_ensure_layer_cache(self)) result.ok = FALSE;
883 .raw_input_kind = DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE,
884 .inputs = request->inputs,
885 };
886 _update_manager_information(state, &end, host, NULL);
887 }
888 break;
889
899 default:
900 break;
901 }
902
903 if(request->release.source)
905
906 _update_manager_information(state, request->inputs ? request : NULL, host, NULL);
907 if(schedule.sync_realtime_mode && self && g)
908 dt_drawlayer_set_pipeline_realtime_mode(self, g->manager.realtime_active);
909
910 return result;
911}
912
914 dt_drawlayer_process_state_t *headless_process,
916 dt_drawlayer_process_state_t *gui_process,
917 const gboolean display_pipe,
918 dt_drawlayer_runtime_manager_t **runtime_manager,
919 dt_drawlayer_process_state_t **runtime_process,
920 gboolean *runtime_display_pipe)
921{
922 if(!IS_NULL_PTR(runtime_manager)) *runtime_manager = display_pipe ? gui_manager : headless_manager;
923 if(!IS_NULL_PTR(runtime_process)) *runtime_process = display_pipe ? gui_process : headless_process;
924 if(!IS_NULL_PTR(runtime_display_pipe)) *runtime_display_pipe = display_pipe;
925}
926
928{
929 if(IS_NULL_PTR(state)) return;
930 memset(state, 0, sizeof(*state));
931 state->cache_imgid = -1;
932 state->cache_layer_order = -1;
933}
934
936{
937 if(IS_NULL_PTR(state)) return;
938 dt_drawlayer_cache_patch_clear(&state->base_patch, "drawlayer patch");
939 dt_drawlayer_cache_patch_clear(&state->stroke_mask, "drawlayer patch");
940 memset(state, 0, sizeof(*state));
941 state->cache_imgid = -1;
942 state->cache_layer_order = -1;
943}
944
946{
947 if(IS_NULL_PTR(state)) return;
948 if(state->stroke_mask.pixels)
949 memset(state->stroke_mask.pixels, 0, (size_t)state->stroke_mask.width * state->stroke_mask.height * sizeof(float));
950}
951
953{
954 if(IS_NULL_PTR(state)) return;
955 dt_drawlayer_cache_patch_clear(&state->stroke_mask, "drawlayer stroke mask");
956 /* Any state invalidation may relocate/free the output buffer this tracked, so
957 * the realtime partial-composite fast path can no longer trust it. */
958 state->last_composite_valid = FALSE;
959 state->last_composite_dev_out = NULL;
960}
961
965{
966 if(IS_NULL_PTR(source)) return;
967
968 if(state && source->tracked_read_lock)
970 FALSE);
971
972 switch(source->kind)
973 {
976 break;
977
979 default:
980 break;
981 }
982
983 *source = (dt_drawlayer_runtime_source_t){ 0 };
984}
985
987{
988 if(IS_NULL_PTR(state)) return;
989 if(state->cursor_surface)
990 {
991 cairo_surface_destroy(state->cursor_surface);
992 state->cursor_surface = NULL;
993 }
994 state->cursor_surface_size = 0;
995 state->cursor_surface_ppd = 0.0;
996 state->cursor_radius = 0.0f;
997 state->cursor_opacity = 0.0f;
998 state->cursor_hardness = 0.0f;
999 state->cursor_shape = -1;
1000 state->cursor_color[0] = state->cursor_color[1] = state->cursor_color[2] = -1.0f;
1001}
__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_log(const char *msg,...)
Definition control.c:824
void dt_control_queue_redraw_center()
Request a redraw of the centre view.
Definition control.c:924
#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:359
void dt_drawlayer_show_runtime_feedback(const dt_iop_drawlayer_gui_data_t *g, const dt_drawlayer_runtime_feedback_t feedback)
Definition drawlayer.c:2703
gboolean dt_drawlayer_sync_widget_cache(dt_iop_module_t *self)
Definition layers.c:469
void dt_drawlayer_begin_gui_stroke_capture(dt_iop_module_t *self, const dt_drawlayer_paint_raw_input_t *first_input)
Definition drawlayer.c:2639
void dt_drawlayer_release_all_base_patch_extra_refs(dt_iop_drawlayer_gui_data_t *g)
Definition drawlayer.c:474
gboolean dt_drawlayer_commit_dabs(dt_iop_module_t *self, gboolean record_history)
Definition drawlayer.c:1754
void dt_drawlayer_set_pipeline_realtime_mode(dt_iop_module_t *self, gboolean state)
Definition layers.c:451
void dt_drawlayer_end_gui_stroke_capture(dt_iop_module_t *self)
Definition drawlayer.c:2662
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:962
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:913
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:687
void dt_drawlayer_process_state_reset_stroke(dt_drawlayer_process_state_t *state)
Definition runtime.c:945
void dt_drawlayer_process_state_init(dt_drawlayer_process_state_t *state)
Definition runtime.c:927
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:445
void dt_drawlayer_ui_cursor_clear(dt_drawlayer_ui_state_t *state)
Definition runtime.c:986
void dt_drawlayer_process_state_cleanup(dt_drawlayer_process_state_t *state)
Definition runtime.c:935
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:475
static void _sync_runtime_state_from_inputs(dt_drawlayer_runtime_manager_t *state, const dt_drawlayer_runtime_inputs_t *inputs)
Definition runtime.c:207
static dt_drawlayer_runtime_private_t * _runtime_private(dt_drawlayer_runtime_manager_t *state)
Definition runtime.c:57
void dt_drawlayer_runtime_manager_note_sidecar_io(dt_drawlayer_runtime_manager_t *state, const gboolean active)
Definition runtime.c:125
void dt_drawlayer_process_state_invalidate(dt_drawlayer_process_state_t *state)
Definition runtime.c:952
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:365
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:664
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:151
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:190
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:250
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:136
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:490
Private runtime state/helpers shared by drawlayer module entrypoints.
dt_drawlayer_runtime_raw_input_kind_t
Definition runtime.h:204
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_NONE
Definition runtime.h:205
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_BEGIN
Definition runtime.h:207
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_STROKE_END
Definition runtime.h:208
@ DT_DRAWLAYER_RUNTIME_RAW_INPUT_SAMPLE
Definition runtime.h:206
@ DT_DRAWLAYER_SOURCE_BASE_PATCH
Definition runtime.h:308
@ DT_DRAWLAYER_SOURCE_NONE
Definition runtime.h:307
dt_drawlayer_runtime_actor_t
Definition runtime.h:160
@ DT_DRAWLAYER_RUNTIME_ACTOR_GUI
Definition runtime.h:162
@ DT_DRAWLAYER_RUNTIME_ACTOR_RASTER_BACKEND
Definition runtime.h:165
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CPU
Definition runtime.h:163
@ DT_DRAWLAYER_RUNTIME_ACTOR_COUNT
Definition runtime.h:167
@ DT_DRAWLAYER_RUNTIME_ACTOR_TIFF_IO
Definition runtime.h:166
@ DT_DRAWLAYER_RUNTIME_ACTOR_NONE
Definition runtime.h:161
@ DT_DRAWLAYER_RUNTIME_ACTOR_PIPELINE_CL
Definition runtime.h:164
dt_drawlayer_runtime_commit_mode_t
Definition runtime.h:212
@ DT_DRAWLAYER_RUNTIME_COMMIT_HISTORY
Definition runtime.h:215
@ DT_DRAWLAYER_RUNTIME_COMMIT_QUIET
Definition runtime.h:214
@ DT_DRAWLAYER_RUNTIME_COMMIT_NONE
Definition runtime.h:213
dt_drawlayer_runtime_buffer_t
Definition runtime.h:171
@ DT_DRAWLAYER_RUNTIME_BUFFER_COUNT
Definition runtime.h:174
@ DT_DRAWLAYER_RUNTIME_BUFFER_BASE_PATCH
Definition runtime.h:172
@ DT_DRAWLAYER_RUNTIME_BUFFER_STROKE_MASK
Definition runtime.h:173
dt_drawlayer_runtime_event_t
Definition runtime.h:178
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_LOAD_END
Definition runtime.h:196
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_GAIN
Definition runtime.h:180
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_LOAD_BEGIN
Definition runtime.h:195
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RESYNC
Definition runtime.h:187
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_AFTER
Definition runtime.h:192
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SCROLL
Definition runtime.h:184
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_BEFORE
Definition runtime.h:193
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_PIPE_FINISHED
Definition runtime.h:188
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CL_AFTER
Definition runtime.h:194
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_CHANGE_IMAGE
Definition runtime.h:186
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_RAW_INPUT
Definition runtime.h:190
@ DT_DRAWLAYER_RUNTIME_EVENT_PROCESS_CPU_BEFORE
Definition runtime.h:191
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_SAVE_END
Definition runtime.h:198
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_LEAVE
Definition runtime.h:183
@ DT_DRAWLAYER_RUNTIME_EVENT_COMMIT_BEGIN
Definition runtime.h:199
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_STROKE_ABORT
Definition runtime.h:189
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_MOUSE_ENTER
Definition runtime.h:182
@ DT_DRAWLAYER_RUNTIME_EVENT_COMMIT_END
Definition runtime.h:200
@ DT_DRAWLAYER_RUNTIME_EVENT_NONE
Definition runtime.h:179
@ DT_DRAWLAYER_RUNTIME_EVENT_SIDECAR_SAVE_BEGIN
Definition runtime.h:197
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_FOCUS_LOSS
Definition runtime.h:181
@ DT_DRAWLAYER_RUNTIME_EVENT_GUI_SYNC_TEMP_BUFFERS
Definition runtime.h:185
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:126
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:297
dt_drawlayer_runtime_request_t runtime
Definition runtime.h:296
const dt_drawlayer_stroke_state_t * stroke
Definition runtime.h:238
const dt_drawlayer_session_state_t * session
Definition runtime.h:236
const char * selected_layer_name
Definition runtime.h:248
const dt_drawlayer_worker_snapshot_t * worker
Definition runtime.h:239
const dt_drawlayer_cache_patch_t * base_patch
Definition runtime.h:240
const dt_drawlayer_process_state_t * process
Definition runtime.h:237
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:330
dt_drawlayer_process_state_t * process
Definition runtime.h:329
const dt_iop_drawlayer_params_t * runtime_params
Definition runtime.h:284
dt_iop_module_t * self
Definition runtime.h:281
dt_iop_drawlayer_gui_data_t * gui
Definition runtime.h:285
dt_drawlayer_process_state_t * process_state
Definition runtime.h:287
const dt_iop_roi_t * roi_out
Definition runtime.h:290
dt_drawlayer_runtime_commit_mode_t commit_mode
Definition runtime.c:421
dt_drawlayer_runtime_feedback_t feedback
Definition runtime.c:423
dt_drawlayer_runtime_buffer_t tracked_buffer
Definition runtime.h:322
dt_drawlayer_runtime_source_kind_t kind
Definition runtime.h:313
dt_drawlayer_runtime_actor_t tracked_actor
Definition runtime.h:323
const dt_drawlayer_runtime_inputs_t * inputs
Definition runtime.h:337
dt_drawlayer_runtime_event_t event
Definition runtime.h:335
dt_drawlayer_runtime_release_t release
Definition runtime.h:339
dt_drawlayer_runtime_raw_input_kind_t raw_input_kind
Definition runtime.h:336
dt_drawlayer_worker_t * worker
Definition runtime.h:73
dt_drawlayer_worker_state_t backend_state
Definition worker.h:41
dt_drawlayer_stroke_state_t stroke
Definition runtime.h:273
dt_drawlayer_runtime_manager_t manager
Definition runtime.h:274
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: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:33
@ DT_DRAWLAYER_WORKER_STATE_BUSY
Definition worker.h:35
@ DT_DRAWLAYER_WORKER_STATE_PAUSED
Definition worker.h:37
@ DT_DRAWLAYER_WORKER_STATE_PAUSING
Definition worker.h:36