From f96a30f5a5c216836710b2aca1c8483df70dc380 Mon Sep 17 00:00:00 2001 From: Hanno Schwalm Date: Sun, 19 Jul 2026 10:56:19 +0200 Subject: [PATCH 1/2] Improve obsolete pipecache handling Currently we use `gboolean cache_obsolete` to enforce a complete invalidation of the pipe's cache before the **next** pixelpipe run. We had that for years, it was introduced and required as a workaround while the hash calculation for piece and cachelines were not "complete". Using the flag leads to bad UI response as a reprocessed pipe will never get a cacheline hit. Instead of using a `gboolean` we now have `uint32_t cache_obsolete_order`, defaulting to INT_MAX. If set to anything below, the cachelines with `iop_order >= cache_obsolete_order` will be invalidated before the next pixelpipe run. This allows a finer control for what cachelines shouldn't be used for a cache-hit thus we have a clearly faster response in many situations triggered by the user. Two helpers were modified, both take the iop_order as an extra argument, note that using an iop_order of `0` will do a complete cache flush (as we had with the old gboolean). `void dt_dev_reprocess_center(dt_develop_t *dev, const int32_t iop_order)` `void dt_dev_reprocess_preview(dt_develop_t *dev, const int32_t iop_order)` --- src/develop/develop.c | 8 ++++---- src/develop/develop.h | 4 ++-- src/develop/pixelpipe_hb.c | 13 +++++++------ src/develop/pixelpipe_hb.h | 4 ++-- src/gui/color_picker_proxy.c | 2 +- src/gui/gtk.c | 2 +- src/iop/ashift.c | 9 +++------ src/iop/channelmixerrgb.c | 4 ++-- src/iop/colorequal.c | 8 ++++---- src/iop/demosaic.c | 12 ++++++------ src/iop/filmicrgb.c | 4 ++-- src/iop/highlights.c | 4 ++-- src/iop/lens.cc | 4 ++-- src/iop/rasterfile.c | 4 ++-- src/iop/retouch.c | 2 +- src/iop/toneequal.c | 6 +++--- src/views/darkroom.c | 34 +++++++++++++++++----------------- 17 files changed, 61 insertions(+), 63 deletions(-) diff --git a/src/develop/develop.c b/src/develop/develop.c index 89296ba62fcb..6375574ca749 100644 --- a/src/develop/develop.c +++ b/src/develop/develop.c @@ -2794,13 +2794,13 @@ void dt_dev_reprocess_all(dt_develop_t *dev) } } -void dt_dev_reprocess_center(dt_develop_t *dev) +void dt_dev_reprocess_center(dt_develop_t *dev, const int32_t iop_order) { DT_GUARD_GUI_UPDATE(); if(dev && dev->gui_attached) { dev->full.pipe->changed |= DT_DEV_PIPE_SYNCH; - dev->full.pipe->cache_obsolete = TRUE; + dev->full.pipe->cache_obsolete_order = iop_order; // invalidate buffers and force redraw of darkroom dt_dev_invalidate_all(dev); @@ -2810,13 +2810,13 @@ void dt_dev_reprocess_center(dt_develop_t *dev) } } -void dt_dev_reprocess_preview(dt_develop_t *dev) +void dt_dev_reprocess_preview(dt_develop_t *dev, const int32_t iop_order) { if(DT_IN_GUI_UPDATE() || !dev || !dev->gui_attached) return; dev->preview_pipe->changed |= DT_DEV_PIPE_SYNCH; - dev->preview_pipe->cache_obsolete = TRUE; + dev->preview_pipe->cache_obsolete_order = iop_order; dt_dev_invalidate_preview(dev); dt_control_queue_redraw_center(); diff --git a/src/develop/develop.h b/src/develop/develop.h index 99f5d610f634..ac6910714cd4 100644 --- a/src/develop/develop.h +++ b/src/develop/develop.h @@ -440,8 +440,8 @@ void dt_dev_toggle_preview2_pinned(dt_develop_t *dev); void dt_dev_pin_image(dt_develop_t *dev, dt_imgid_t imgid); void dt_dev_set_histogram_pre(dt_develop_t *dev); void dt_dev_reprocess_all(dt_develop_t *dev); -void dt_dev_reprocess_center(dt_develop_t *dev); -void dt_dev_reprocess_preview(dt_develop_t *dev); +void dt_dev_reprocess_center(dt_develop_t *dev, const int32_t iop_order); +void dt_dev_reprocess_preview(dt_develop_t *dev, const int32_t iop_order); gboolean dt_dev_get_preview_size(const dt_develop_t *dev, float *wd, diff --git a/src/develop/pixelpipe_hb.c b/src/develop/pixelpipe_hb.c index beb4f4004ad6..a1be7da2428a 100644 --- a/src/develop/pixelpipe_hb.c +++ b/src/develop/pixelpipe_hb.c @@ -273,7 +273,7 @@ gboolean dt_dev_pixelpipe_init_cached(dt_dev_pixelpipe_t *pipe, pipe->processed_height = pipe->backbuf_height = pipe->iheight = pipe->final_height = 0; pipe->nodes = NULL; pipe->backbuf_size = size; - pipe->cache_obsolete = FALSE; + pipe->cache_obsolete_order = INT_MAX; pipe->backbuf = NULL; pipe->backbuf_scale = 0.0f; memset(pipe->backbuf_zoom_pos, 0, sizeof(dt_dev_zoom_pos_t)); @@ -466,9 +466,9 @@ void dt_dev_pixelpipe_rebuild(dt_develop_t *dev) dev->preview_pipe->changed |= DT_DEV_PIPE_REMOVE; dev->preview2.pipe->changed |= DT_DEV_PIPE_REMOVE; - dev->full.pipe->cache_obsolete = TRUE; - dev->preview_pipe->cache_obsolete = TRUE; - dev->preview2.pipe->cache_obsolete = TRUE; + dev->full.pipe->cache_obsolete_order = 0; + dev->preview_pipe->cache_obsolete_order = 0; + dev->preview2.pipe->cache_obsolete_order = 0; // invalidate buffers and force redraw of darkroom dt_dev_invalidate_all(dev); @@ -3099,8 +3099,9 @@ gboolean dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, restart: // check if we should obsolete caches - if(pipe->cache_obsolete) dt_dev_pixelpipe_cache_flush(pipe); - pipe->cache_obsolete = FALSE; + if(pipe->cache_obsolete_order != INT_MAX) + dt_dev_pixelpipe_cache_invalidate_later(pipe, pipe->cache_obsolete_order, "pre pixelpipe run"); + pipe->cache_obsolete_order = INT_MAX; // mask display off as a starting point pipe->mask_display = DT_DEV_PIXELPIPE_DISPLAY_NONE; diff --git a/src/develop/pixelpipe_hb.h b/src/develop/pixelpipe_hb.h index 0c0acea08819..b907e66521bd 100644 --- a/src/develop/pixelpipe_hb.h +++ b/src/develop/pixelpipe_hb.h @@ -159,8 +159,8 @@ typedef struct dt_dev_pixelpipe_t { // store history/zoom caches dt_dev_pixelpipe_cache_t cache; - // set to TRUE in order to obsolete old cache entries on next pixelpipe run - gboolean cache_obsolete; + // set to an iop_order to invalidate cachelines >= given order before next pixelpipe run + uint32_t cache_obsolete_order; uint64_t runs; // used only for pixelpipe cache statistics // input buffer float *input; diff --git a/src/gui/color_picker_proxy.c b/src/gui/color_picker_proxy.c index 7b2a59e37a79..5d41713689eb 100644 --- a/src/gui/color_picker_proxy.c +++ b/src/gui/color_picker_proxy.c @@ -300,7 +300,7 @@ static void _iop_color_picker_pickerdata_ready_callback(gpointer instance, // will set the work_profile if needed. // FIXME: is this overdoing it? see #14812 pipe->changed |= DT_DEV_PIPE_REMOVE; - pipe->cache_obsolete = TRUE; + pipe->cache_obsolete_order = module->iop_order; // iops only need new picker data if the pointer has moved if(_record_point_area(picker)) diff --git a/src/gui/gtk.c b/src/gui/gtk.c index 32fc10563c8b..fba469abdeda 100644 --- a/src/gui/gtk.c +++ b/src/gui/gtk.c @@ -226,7 +226,7 @@ static void _focuspeaking_switch_button_callback(GtkWidget *button, gtk_widget_queue_draw(button); // make sure the second window if active is updated - dt_dev_reprocess_center(darktable.develop); + dt_dev_reprocess_center(darktable.develop, INT_MAX); // we inform that all thumbnails need to be redraw DT_CONTROL_SIGNAL_RAISE(DT_SIGNAL_DEVELOP_MIPMAP_UPDATED, -1); diff --git a/src/iop/ashift.c b/src/iop/ashift.c index 0c83fc1a9597..9befd6093dea 100644 --- a/src/iop/ashift.c +++ b/src/iop/ashift.c @@ -3212,8 +3212,7 @@ static gboolean _do_get_structure_auto(dt_iop_module_t *self, { dt_control_log(_("data pending - please repeat")); // force to reprocess the preview, otherwise the buffer is ko - dt_dev_pixelpipe_cache_flush(self->dev->preview_pipe); - dt_dev_reprocess_preview(self->dev); + dt_dev_reprocess_preview(self->dev, self->iop_order); goto error; } @@ -3264,8 +3263,7 @@ static void _do_get_structure_lines(dt_iop_module_t *self) { dt_control_log(_("data pending - please repeat")); // force to reprocess the preview, otherwise the buffer is ko - dt_dev_pixelpipe_cache_flush(self->dev->preview_pipe); - dt_dev_reprocess_preview(self->dev); + dt_dev_reprocess_preview(self->dev, self->iop_order); return; } @@ -3311,8 +3309,7 @@ static void _do_get_structure_quad(dt_iop_module_t *self) { dt_control_log(_("data pending - please repeat")); // force to reprocess the preview, otherwise the buffer is ko - dt_dev_pixelpipe_cache_flush(self->dev->preview_pipe); - dt_dev_reprocess_preview(self->dev); + dt_dev_reprocess_preview(self->dev, self->iop_order); return; } diff --git a/src/iop/channelmixerrgb.c b/src/iop/channelmixerrgb.c index 87e8c003fa05..ed81b44bdb3a 100644 --- a/src/iop/channelmixerrgb.c +++ b/src/iop/channelmixerrgb.c @@ -2914,7 +2914,7 @@ static void _run_profile_callback(GtkWidget *widget, g->run_profile = TRUE; dt_iop_gui_leave_critical_section(self); - dt_dev_reprocess_preview(self->dev); + dt_dev_reprocess_preview(self->dev, self->iop_order); } static void _run_validation_callback(GtkWidget *widget, @@ -2927,7 +2927,7 @@ static void _run_validation_callback(GtkWidget *widget, g->run_validation = TRUE; dt_iop_gui_leave_critical_section(self); - dt_dev_reprocess_preview(self->dev); + dt_dev_reprocess_preview(self->dev, self->iop_order); } static void _commit_profile_callback(GtkWidget *widget, diff --git a/src/iop/colorequal.c b/src/iop/colorequal.c index dfadc4c5b342..eddb6326142a 100644 --- a/src/iop/colorequal.c +++ b/src/iop/colorequal.c @@ -2243,7 +2243,7 @@ void gui_focus(dt_iop_module_t *self, gboolean in) dt_bauhaus_widget_set_quad_active(g->threshold, FALSE); dt_bauhaus_widget_set_quad_active(g->hue_shift, FALSE); g->mask_mode = 0; - if(buttons) dt_dev_reprocess_center(self->dev); + if(buttons) dt_dev_reprocess_center(self->dev, self->iop_order); } } @@ -2568,7 +2568,7 @@ static void _masking_callback_p(GtkWidget *quad, dt_iop_module_t *self) dt_iop_colorequal_gui_data_t *g = self->gui_data; dt_bauhaus_widget_set_quad_active(g->threshold, FALSE); g->mask_mode = (dt_bauhaus_widget_get_quad_active(quad)) ? g->channel + 1 : 0; - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } static void _masking_callback_t(GtkWidget *quad, dt_iop_module_t *self) @@ -2577,7 +2577,7 @@ static void _masking_callback_t(GtkWidget *quad, dt_iop_module_t *self) dt_iop_colorequal_gui_data_t *g = self->gui_data; dt_bauhaus_widget_set_quad_active(g->param_size, FALSE); g->mask_mode = (dt_bauhaus_widget_get_quad_active(quad)) ? GRAD_SWITCH + g->channel + 1 : 0; - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } static void _channel_tabs_switch_callback(GtkNotebook *notebook, @@ -2607,7 +2607,7 @@ static void _channel_tabs_switch_callback(GtkNotebook *notebook, g->mask_mode = masking_p ? g->channel + 1 : (masking_t ? GRAD_SWITCH + g->channel + 1 : 0); if(g->mask_mode != old_mask_mode) - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); gtk_widget_queue_draw(GTK_WIDGET(g->area)); } diff --git a/src/iop/demosaic.c b/src/iop/demosaic.c index 0844af982591..aec53b74706e 100644 --- a/src/iop/demosaic.c +++ b/src/iop/demosaic.c @@ -1636,7 +1636,7 @@ static void _dual_thrs_callback(GtkWidget *quad, dt_iop_module_t *self) dt_bauhaus_widget_set_quad_active(g->cs_boost, FALSE); g->cs_boost_mask = FALSE; - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } static void _cs_thrs_callback(GtkWidget *quad, dt_iop_module_t *self) @@ -1650,7 +1650,7 @@ static void _cs_thrs_callback(GtkWidget *quad, dt_iop_module_t *self) dt_bauhaus_widget_set_quad_active(g->cs_boost, FALSE); g->cs_boost_mask = FALSE; - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } static void _cs_boost_callback(GtkWidget *quad, dt_iop_module_t *self) @@ -1664,7 +1664,7 @@ static void _cs_boost_callback(GtkWidget *quad, dt_iop_module_t *self) dt_bauhaus_widget_set_quad_active(g->cs_thrs, FALSE); g->cs_mask = FALSE; - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } static void _cs_radius_callback(GtkWidget *quad, dt_iop_module_t *self) @@ -1672,7 +1672,7 @@ static void _cs_radius_callback(GtkWidget *quad, dt_iop_module_t *self) DT_GUARD_GUI_UPDATE(); dt_iop_demosaic_gui_data_t *g = self->gui_data; g->new_radius = -1.0f; - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } static void _ui_pipe_done(gpointer instance, dt_iop_module_t *self) @@ -1709,7 +1709,7 @@ static void _preset_applied_callback(gpointer instance, dt_iop_module_t *self) { dt_print(DT_DEBUG_PIPE, "demosaic auto preset applied, radius=%.3f thrs=%.3f", p->cs_radius, p->cs_thrs); - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } } @@ -1726,7 +1726,7 @@ void gui_focus(dt_iop_module_t *self, const gboolean in) dt_bauhaus_widget_set_quad_active(g->cs_boost, FALSE); g->cs_boost_mask = FALSE; - if(was_masking) dt_dev_reprocess_center(self->dev); + if(was_masking) dt_dev_reprocess_center(self->dev, self->iop_order); } } diff --git a/src/iop/filmicrgb.c b/src/iop/filmicrgb.c index edae7f5ebca4..28cb5c3b8477 100644 --- a/src/iop/filmicrgb.c +++ b/src/iop/filmicrgb.c @@ -2720,7 +2720,7 @@ static void show_mask_callback(GtkToggleButton *button, GdkEventButton *event, c g->show_mask = !(g->show_mask); gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->show_highlight_mask), g->show_mask); DT_LEAVE_GUI_UPDATE(); - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } #define ORDER_4 5 @@ -3111,7 +3111,7 @@ void gui_focus(dt_iop_module_t *self, gboolean in) const gint mask_was_shown = g->show_mask; g->show_mask = FALSE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->show_highlight_mask), FALSE); - if(mask_was_shown) dt_dev_reprocess_center(self->dev); + if(mask_was_shown) dt_dev_reprocess_center(self->dev, self->iop_order); } } diff --git a/src/iop/highlights.c b/src/iop/highlights.c index 01ab23ad8bf0..46e075dff902 100644 --- a/src/iop/highlights.c +++ b/src/iop/highlights.c @@ -1258,7 +1258,7 @@ static void _quad_callback(GtkWidget *quad, dt_iop_module_t *self) DT_GUARD_GUI_UPDATE(); dt_iop_highlights_gui_data_t *g = self->gui_data; _set_quads(g, quad); - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } void gui_focus(dt_iop_module_t *self, gboolean in) @@ -1268,7 +1268,7 @@ void gui_focus(dt_iop_module_t *self, gboolean in) { const gboolean was_visualize = (g->hlr_mask_mode != DT_HIGHLIGHTS_MASK_OFF); _set_quads(g, NULL); - if(was_visualize) dt_dev_reprocess_center(self->dev); + if(was_visualize) dt_dev_reprocess_center(self->dev, self->iop_order); } } diff --git a/src/iop/lens.cc b/src/iop/lens.cc index 89ff6a50bcb8..14d789856da0 100644 --- a/src/iop/lens.cc +++ b/src/iop/lens.cc @@ -4357,7 +4357,7 @@ static void _visualize_callback(GtkWidget *quad, DT_GUARD_GUI_UPDATE(); dt_iop_lens_gui_data_t *g = (dt_iop_lens_gui_data_t *)self->gui_data; g->vig_masking = dt_bauhaus_widget_get_quad_active(quad); - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } void gui_init(dt_iop_module_t *self) @@ -4611,7 +4611,7 @@ void gui_focus(dt_iop_module_t *self, gboolean in) dt_bauhaus_widget_set_quad_active(g->v_strength, FALSE); g->vig_masking = FALSE; if(was_visualize) - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } _display_errors(self); } diff --git a/src/iop/rasterfile.c b/src/iop/rasterfile.c index e2a77257397c..a1a55fa97dd1 100644 --- a/src/iop/rasterfile.c +++ b/src/iop/rasterfile.c @@ -673,7 +673,7 @@ void gui_changed(dt_iop_module_t *self, dt_pthread_mutex_unlock(&cd->lock); if(other) - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } gtk_widget_set_sensitive(g->vectorize, p->path[0] && p->file[0]); @@ -730,7 +730,7 @@ void cleanup(dt_iop_module_t *self) void gui_focus(dt_iop_module_t *self, gboolean in) { - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); } void gui_init(dt_iop_module_t *self) diff --git a/src/iop/retouch.c b/src/iop/retouch.c index 1ce4a9ddc2bc..65ab47e4dcf2 100644 --- a/src/iop/retouch.c +++ b/src/iop/retouch.c @@ -1704,7 +1704,7 @@ static gboolean rt_display_wavelet_scale_callback(GtkToggleButton *togglebutton, } dt_iop_gui_leave_critical_section(self); - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); gtk_toggle_button_set_active(togglebutton, g->display_wavelet_scale); return TRUE; diff --git a/src/iop/toneequal.c b/src/iop/toneequal.c index 7b6440c4d88e..b460e5de5e0b 100644 --- a/src/iop/toneequal.c +++ b/src/iop/toneequal.c @@ -1948,7 +1948,7 @@ static void show_luminance_mask_callback(GtkWidget *togglebutton, g->mask_display = !g->mask_display; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->show_luminance_mask), g->mask_display); -// dt_dev_reprocess_center(self->dev); +// dt_dev_reprocess_center(self->dev, self->iop_order); dt_iop_refresh_center(self); // Unlock the colour picker so we can display our own custom cursor @@ -2517,7 +2517,7 @@ static void _develop_distort_callback(gpointer instance, /* we do reprocess the preview to get a new internal image buffer with the proper image geometry. */ if(self->enabled) - dt_dev_reprocess_preview(darktable.develop); + dt_dev_reprocess_preview(darktable.develop, self->iop_order); } static void _set_distort_signal(dt_iop_module_t *self) @@ -2554,7 +2554,7 @@ void gui_focus(dt_iop_module_t *self, const gboolean in) g->mask_display = FALSE; gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(g->show_luminance_mask), FALSE); if(was_mask) - dt_dev_reprocess_center(self->dev); + dt_dev_reprocess_center(self->dev, self->iop_order); dt_collection_hint_message(darktable.collection); // no need for the distort signal anymore diff --git a/src/views/darkroom.c b/src/views/darkroom.c index 0ad5215b4af8..edd265cef8ec 100644 --- a/src/views/darkroom.c +++ b/src/views/darkroom.c @@ -1746,7 +1746,7 @@ static void _color_assessment_border_white_ratio_callback(GtkWidget *slider, gpo dt_conf_set_float("darkroom/ui/color_assessment_border_white_ratio", dt_bauhaus_slider_get(slider)); if (dev->full.color_assessment) { - dt_dev_reprocess_center(dev); + dt_dev_reprocess_center(dev, INT_MAX); } else { @@ -1781,7 +1781,7 @@ static void _latescaling_quickbutton_clicked(GtkWidget *w, if(dev->second_wnd) dt_dev_reprocess_all(dev); else - dt_dev_reprocess_center(dev); + dt_dev_reprocess_center(dev, 0); } } @@ -1808,7 +1808,7 @@ static void _overexposed_quickbutton_clicked(GtkWidget *w, dt_develop_t *d = (dt_develop_t *)user_data; d->overexposed.enabled = !d->overexposed.enabled; dt_conf_set_bool("darkroom/ui/overexposed/enabled", d->overexposed.enabled); - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, INT_MAX); } static void _colorscheme_callback(GtkWidget *combo, @@ -1819,7 +1819,7 @@ static void _colorscheme_callback(GtkWidget *combo, if(d->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->overexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } static void _lower_callback(GtkWidget *slider, @@ -1830,7 +1830,7 @@ static void _lower_callback(GtkWidget *slider, if(d->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->overexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } static void _upper_callback(GtkWidget *slider, @@ -1841,7 +1841,7 @@ static void _upper_callback(GtkWidget *slider, if(d->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->overexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } static void _mode_callback(GtkWidget *slider, @@ -1852,7 +1852,7 @@ static void _mode_callback(GtkWidget *slider, if(d->overexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->overexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } /* rawoverexposed */ @@ -1862,7 +1862,7 @@ static void _rawoverexposed_quickbutton_clicked(GtkWidget *w, dt_develop_t *d = (dt_develop_t *)user_data; d->rawoverexposed.enabled = !d->rawoverexposed.enabled; dt_conf_set_bool("darkroom/ui/rawoverexposed/enabled", d->rawoverexposed.enabled); - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, INT_MAX); } static void _rawoverexposed_mode_callback(GtkWidget *combo, @@ -1873,7 +1873,7 @@ static void _rawoverexposed_mode_callback(GtkWidget *combo, if(d->rawoverexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->rawoverexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } static void _rawoverexposed_colorscheme_callback(GtkWidget *combo, @@ -1884,7 +1884,7 @@ static void _rawoverexposed_colorscheme_callback(GtkWidget *combo, if(d->rawoverexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->rawoverexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } static void _rawoverexposed_threshold_callback(GtkWidget *slider, @@ -1895,7 +1895,7 @@ static void _rawoverexposed_threshold_callback(GtkWidget *slider, if(d->rawoverexposed.enabled == FALSE) gtk_button_clicked(GTK_BUTTON(d->rawoverexposed.button)); else - dt_dev_reprocess_center(d); + dt_dev_reprocess_center(d, 0); } /* softproof */ @@ -1909,8 +1909,8 @@ static void _softproof_quickbutton_clicked(GtkWidget *w, darktable.color_profiles->mode = DT_PROFILE_SOFTPROOF; _update_softproof_gamut_checking(d); - - dt_dev_reprocess_center(d); + dt_iop_module_t *cout = dt_iop_get_module("colorout"); + dt_dev_reprocess_center(d, cout ? cout->iop_order : 0); } /* gamut */ @@ -1924,8 +1924,8 @@ static void _gamut_quickbutton_clicked(GtkWidget *w, darktable.color_profiles->mode = DT_PROFILE_GAMUTCHECK; _update_softproof_gamut_checking(d); - - dt_dev_reprocess_center(d); + dt_iop_module_t *cout = dt_iop_get_module("colorout"); + dt_dev_reprocess_center(d, cout ? cout->iop_order : 0); } /* set the gui state for both softproof and gamut checking */ @@ -4680,7 +4680,7 @@ static gboolean _second_window_configure_callback(GtkWidget *da, // pipe needs to be reconstructed dev->preview2.pipe->status = DT_DEV_PIXELPIPE_DIRTY; dev->preview2.pipe->changed |= DT_DEV_PIPE_REMOVE; - dev->preview2.pipe->cache_obsolete = TRUE; + dev->preview2.pipe->cache_obsolete_order = 0; // If we have a pinned image, update its viewport dimensions too dt_develop_t *pinned_dev = dev->preview2_pinned ? dev->preview2_pinned_dev : NULL; @@ -4693,7 +4693,7 @@ static gboolean _second_window_configure_callback(GtkWidget *da, pinned_port->orig_height = event->height; pinned_port->pipe->status = DT_DEV_PIXELPIPE_DIRTY; pinned_port->pipe->changed |= DT_DEV_PIPE_REMOVE; - pinned_port->pipe->cache_obsolete = TRUE; + pinned_port->pipe->cache_obsolete_order = 0; } } From 8b35115a20f9f16a4b77fa0677420ce7d2e256c5 Mon Sep 17 00:00:00 2001 From: Hanno Schwalm Date: Sun, 19 Jul 2026 17:08:26 +0200 Subject: [PATCH 2/2] More simplify of cache invalidations 1. Request for details mask 2. Selecting a history item in history lib both require cacheline invalidations, simplyfied code in both cases. --- src/develop/pixelpipe_hb.c | 25 +++++++------------------ src/develop/pixelpipe_hb.h | 2 -- src/libs/history.c | 11 +---------- 3 files changed, 8 insertions(+), 30 deletions(-) diff --git a/src/develop/pixelpipe_hb.c b/src/develop/pixelpipe_hb.c index a1be7da2428a..11c452931f88 100644 --- a/src/develop/pixelpipe_hb.c +++ b/src/develop/pixelpipe_hb.c @@ -530,6 +530,7 @@ static void _dev_pixelpipe_synch(dt_dev_pixelpipe_t *pipe, const dt_image_t *img = &pipe->image; const dt_imgid_t imgid = img->id; const gboolean rawprep_img = dt_image_is_rawprepare_supported(img); + const gboolean raw_img = dt_image_is_raw(img); for(GList *nodes = pipe->nodes; nodes; nodes = g_list_next(nodes)) { @@ -628,8 +629,12 @@ static void _dev_pixelpipe_synch(dt_dev_pixelpipe_t *pipe, const dt_develop_blend_params_t *const bp = piece->blendop_data; const gboolean valid_mask = bp->mask_mode > DEVELOP_MASK_ENABLED; - if(!feqf(bp->details, 0.0f, 1e-6) && valid_mask) - dt_dev_pixelpipe_usedetails(piece); + if(!feqf(bp->details, 0.0f, 1e-6) && valid_mask && pipe->want_detail_mask == FALSE) + { + dt_iop_module_t *gen = raw_img ? dt_iop_get_module("demosaic") : NULL; + dt_dev_pixelpipe_cache_invalidate_later(pipe, gen ? gen->iop_order : 0, "usedetails "); + pipe->want_detail_mask = TRUE; + } } } } @@ -664,11 +669,6 @@ void dt_dev_pixelpipe_synch_all(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev) dt_dev_clear_scharr_mask(pipe); pipe->want_detail_mask = FALSE; - /* go through all history items and adjust params - We might call dt_dev_pixelpipe_usedetails() with want_detail_mask == FALSE - here resulting in a pipecache invalidation. - Can this somehow be avoided? - */ GList *history = dev->history; for(int k = 0; k < dev->history_end && history; k++) { @@ -749,17 +749,6 @@ void dt_dev_pixelpipe_change(dt_dev_pixelpipe_t *pipe, dt_develop_t *dev) &pipe->processed_height); } -void dt_dev_pixelpipe_usedetails(dt_dev_pixelpipe_iop_t *piece) -{ - dt_dev_pixelpipe_t *pipe = piece->pipe; - if(!pipe->want_detail_mask) - { - dt_print_pipe(DT_DEBUG_PIPE, "details requested", pipe, piece->module, DT_DEVICE_NONE, NULL, NULL); - dt_dev_pixelpipe_cache_invalidate_later(pipe, 0, "usedetails "); - pipe->want_detail_mask = TRUE; - } -} - static void _dump_pipe_pfm_diff(const char *mod, const void *indata, const dt_iop_roi_t *roi_in, diff --git a/src/develop/pixelpipe_hb.h b/src/develop/pixelpipe_hb.h index b907e66521bd..79cf24a7a979 100644 --- a/src/develop/pixelpipe_hb.h +++ b/src/develop/pixelpipe_hb.h @@ -397,8 +397,6 @@ void dt_dev_pixelpipe_synch_top(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *d // force a rebuild of the pipe, needed when a module order is changed for example void dt_dev_pixelpipe_rebuild(struct dt_develop_t *dev); -// switch on details mask processing -void dt_dev_pixelpipe_usedetails(dt_dev_pixelpipe_iop_t *piece); // process region of interest of pixels. returns TRUE if pipe was altered during processing. gboolean dt_dev_pixelpipe_process(dt_dev_pixelpipe_t *pipe, struct dt_develop_t *dev, diff --git a/src/libs/history.c b/src/libs/history.c index 13f8fd2632db..4f181c05f015 100644 --- a/src/libs/history.c +++ b/src/libs/history.c @@ -1303,16 +1303,7 @@ static gboolean _lib_history_button_clicked_callback(GtkWidget *widget, dt_dev_reorder_gui_module_list(darktable.develop); dt_image_update_final_size(imgid); - /* FIXME - The pixelpipe cache is reflecting parameters and it's related output correctness. - Yet - there are modules that require fresh data for internal visualizing. - As there is currently no way to know about that we do a brute-force way and simply - invalidate cachelines. - (we might want an additional iop module flag and keep track of that in pixelpipe cache code ???) - For raws we have at least rawprepare and demosaic - */ - const int order = dt_image_is_raw(&darktable.develop->image_storage) ? 2 : 0; - dt_dev_pixelpipe_cache_invalidate_later(darktable.develop->preview_pipe, order, "history button: "); + dt_dev_pixelpipe_cache_invalidate_later(darktable.develop->preview_pipe, 0, "history button: "); /* signal history changed */ dt_dev_undo_end_record(darktable.develop);