Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
pixelpipe_gui.c File Reference

Pixelpipe GUI sampling helpers (histograms + color picker). More...

#include "common/color_picker.h"
#include "common/darktable.h"
#include "common/histogram.h"
#include "common/iop_order.h"
#include "control/signal.h"
#include "develop/blend.h"
#include "develop/pixelpipe.h"
#include "develop/pixelpipe_cache.h"
#include "gui/color_picker_proxy.h"
#include "libs/colorpicker.h"
#include <math.h>
#include <string.h>
+ Include dependency graph for pixelpipe_gui.c:
+ This graph shows which files directly or indirectly include this file:

Go to the source code of this file.

Typedefs

typedef enum dt_pixelpipe_picker_source_t dt_pixelpipe_picker_source_t
 Identify whether the picker sampling is applied on the module input or output.
 

Enumerations

enum  dt_pixelpipe_picker_source_t {
  PIXELPIPE_PICKER_INPUT = 0 ,
  PIXELPIPE_PICKER_OUTPUT = 1
}
 Identify whether the picker sampling is applied on the module input or output. More...
 

Functions

static void histogram_collect (dt_dev_pixelpipe_iop_t *piece, const void *pixel, const dt_iop_roi_t roi, uint32_t **histogram, uint32_t *histogram_max)
 Compute a histogram for a given module piece.
 
static dt_backbuf_t_get_backuf (dt_develop_t *dev, const char *op)
 Map an op name to the corresponding global histogram backbuffer.
 
static void pixelpipe_get_histogram_backbuf (dt_develop_t *dev, const dt_iop_roi_t roi, dt_pixel_cache_entry_t *entry, dt_iop_module_t *module, const uint64_t hash)
 Update the global histogram backbuffer to reference a specific cache entry.
 
static gboolean _pipe_tracks_gui_observables (const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev)
 
static gboolean _module_requests_color_picker (const dt_develop_t *dev, const dt_iop_module_t *module)
 
static gboolean _module_requests_input_histogram (const dt_develop_t *dev, const dt_dev_pixelpipe_iop_t *piece)
 
static gboolean _module_needs_gui_host_input_sampling (const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev, const dt_iop_module_t *module, const dt_dev_pixelpipe_iop_t *piece)
 
static gboolean _module_needs_gui_output_backbuf_sync (const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev, const dt_iop_module_t *module)
 
static gboolean _module_needs_gui_input_backbuf_sync (const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev, const dt_iop_module_t *module)
 
static gboolean _pipe_needs_gui_sampling_traversal (const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev)
 
static gboolean _module_exact_hit_must_recurse_for_picker (const dt_dev_pixelpipe_t *pipe, const dt_develop_t *dev, const dt_iop_module_t *module)
 Tell whether an exact cache hit must still recurse to reach the active color picker module.
 
static void _sync_module_output_backbuf_on_exact_hit (dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_pixel_cache_entry_t *output_entry, const dt_iop_roi_t roi_out, const uint64_t hash)
 
static int pixelpipe_picker_helper (dt_iop_module_t *module, const dt_iop_roi_t roi, dt_aligned_pixel_t picked_color, dt_aligned_pixel_t picked_color_min, dt_aligned_pixel_t picked_color_max, dt_pixelpipe_picker_source_t picker_source, int *box)
 Compute the sampling box in module coordinates for the interactive color picker.
 
static void pixelpipe_picker (dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, dt_iop_buffer_dsc_t *dsc, const float *pixel, const dt_iop_roi_t roi, float *picked_color, float *picked_color_min, float *picked_color_max, const dt_iop_colorspace_type_t image_cst, dt_pixelpipe_picker_source_t picker_source)
 Sample the color picker values (avg/min/max) from a pixel buffer.
 
static dt_iop_colorspace_type_t _transform_for_picker (dt_iop_module_t *self, const dt_iop_colorspace_type_t cst)
 Select a safe colorspace for picker sampling.
 
static void collect_histogram_on_CPU (dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input, const dt_iop_roi_t roi_in, dt_iop_buffer_dsc_t *input_format, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece)
 Collect the per-module histogram on CPU for GUI display.
 
static void _sample_color_picker (dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, float *input, dt_iop_buffer_dsc_t *input_format, const dt_iop_roi_t roi_in, void **output, dt_iop_buffer_dsc_t **out_format, const dt_iop_roi_t roi_out, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece)
 Sample the interactive color picker for the currently edited module.
 
static void _sample_gui (dt_dev_pixelpipe_t *pipe, dt_develop_t *dev, void *input, void **output, const dt_iop_roi_t roi_in, const dt_iop_roi_t roi_out, dt_iop_buffer_dsc_t *input_format, dt_iop_buffer_dsc_t **output_format, dt_iop_module_t *module, dt_dev_pixelpipe_iop_t *piece, const uint64_t input_hash, const uint64_t hash, const size_t in_bpp, const size_t bpp, dt_pixel_cache_entry_t *const input_entry, dt_pixel_cache_entry_t *const output_entry)
 Sample all GUI observables for a processed module node.
 
static gboolean _resync_global_histograms (dt_dev_pixelpipe_t *pipe, dt_develop_t *dev)
 Re-sync the global histogram cache references on a pure cache hit.
 

Detailed Description

Pixelpipe GUI sampling helpers (histograms + color picker).

This file centralizes the code paths that exist only to feed the GUI:

  • per-module histograms (small, module-local),
  • the global "raw/output/display" histograms stored in dt_develop_t,
  • the interactive color picker (box/point sample) used by the currently edited module.

Why this is separate from the pixel processing code

The pixelpipe (in pixelpipe_hb.c) is primarily a functional pipeline: "given an input buffer + module params → compute an output buffer".

GUI sampling is different:

  • it is conditional on the GUI being attached,
  • it depends on current UI state (which module is active, which picker sample is enabled),
  • it may require special-case handling (e.g. gamma outputs uint8_t, but we want float32 for histograms),
  • it must obey the pixelpipe cache invariants (locks + refcounts) while reading data.

This means it adds complexity and cross-cutting concerns that should not pollute the main processing code.

Caveats / expectations (read this before editing)

1) GUI-observable pipes only These helpers are intended for pipes advertising pipe->gui_observable_source when dev->gui_attached is true. They must not be invoked for exports or background processing.

2) Cache entries are the source of truth The GUI should never access transient buffers directly. We always sample through cache entries, with appropriate cache locks, because the cache controls lifetime and eviction.

3) Gamma special case The gamma module produces uint8 output for display. Histograms and picker sampling expect float buffers. Therefore global histogram sampling for gamma uses the input cache entry, not the output.

4) Distortion backtransform for picker The picker position is expressed in final preview coordinates. We must backtransform it to the module coordinates, and the transform direction depends on whether we sample input or output.

5) OpenCL is not involved here GUI sampling runs on host buffers (RAM). Any OpenCL device buffers must have been synchronized into the cache earlier in the control flow (by design, the GUI always samples cache-backed host buffers).

6) In-place colorspace conversions Some sampling paths perform colorspace conversions in-place to make values meaningful to the user. This relies on higher-level pixelpipe control flow ensuring those buffers are not used afterward in a way that would be corrupted by the conversion (typically this is guarded by module activation / forced caching). If you change where these helpers are called, revisit those assumptions.

Typedef Documentation

◆ dt_pixelpipe_picker_source_t

Identify whether the picker sampling is applied on the module input or output.

The GUI lets users request either:

  • sampling values at the module input ("what does this module receive?"), or
  • sampling values at the module output ("what does this module produce?").

This choice affects:

  • which buffer we sample (input vs *output),
  • the distortion backtransform direction (include/exclude the current module transform),
  • and the colorspace metadata attached to the sample.

Enumeration Type Documentation

◆ dt_pixelpipe_picker_source_t

Identify whether the picker sampling is applied on the module input or output.

The GUI lets users request either:

  • sampling values at the module input ("what does this module receive?"), or
  • sampling values at the module output ("what does this module produce?").

This choice affects:

  • which buffer we sample (input vs *output),
  • the distortion backtransform direction (include/exclude the current module transform),
  • and the colorspace metadata attached to the sample.
Enumerator
PIXELPIPE_PICKER_INPUT 
PIXELPIPE_PICKER_OUTPUT 

Function Documentation

◆ _get_backuf()

static dt_backbuf_t * _get_backuf ( dt_develop_t dev,
const char *  op 
)
static

Map an op name to the corresponding global histogram backbuffer.

Returns
A pointer to one of dev->raw_histogram, dev->output_histogram, dev->display_histogram, or NULL if the module is not wired to a global histogram.

The develop module maintains three global histograms for UI display. We keep references to the cache entries feeding those histograms so that the underlying buffers are not evicted while the GUI reads them.

References dt_develop_t::display_histogram, dt_develop_t::output_histogram, and dt_develop_t::raw_histogram.

Referenced by _resync_global_histograms(), _set_opencl_cache(), and pixelpipe_get_histogram_backbuf().

◆ _module_exact_hit_must_recurse_for_picker()

static gboolean _module_exact_hit_must_recurse_for_picker ( const dt_dev_pixelpipe_t pipe,
const dt_develop_t dev,
const dt_iop_module_t module 
)
inlinestatic

Tell whether an exact cache hit must still recurse to reach the active color picker module.

Moving a picker changes only the sampled coordinates, not the module output hashes. This means downstream modules can exact-hit in cache while an upstream GUI module still needs fresh host-buffer sampling to emit DT_SIGNAL_CONTROL_PICKERDATA_READY.

If we returned early from those downstream exact hits, the recursion would never reach the active GUI module and the picker would move on screen without updating any parameter.

References _pipe_tracks_gui_observables().

Referenced by dt_dev_pixelpipe_process_rec().

◆ _module_needs_gui_host_input_sampling()

static gboolean _module_needs_gui_host_input_sampling ( const dt_dev_pixelpipe_t pipe,
const dt_develop_t dev,
const dt_iop_module_t module,
const dt_dev_pixelpipe_iop_t piece 
)
inlinestatic

◆ _module_needs_gui_input_backbuf_sync()

static gboolean _module_needs_gui_input_backbuf_sync ( const dt_dev_pixelpipe_t pipe,
const dt_develop_t dev,
const dt_iop_module_t module 
)
inlinestatic

◆ _module_needs_gui_output_backbuf_sync()

static gboolean _module_needs_gui_output_backbuf_sync ( const dt_dev_pixelpipe_t pipe,
const dt_develop_t dev,
const dt_iop_module_t module 
)
inlinestatic

◆ _module_requests_color_picker()

static gboolean _module_requests_color_picker ( const dt_develop_t dev,
const dt_iop_module_t module 
)
inlinestatic

◆ _module_requests_input_histogram()

static gboolean _module_requests_input_histogram ( const dt_develop_t dev,
const dt_dev_pixelpipe_iop_t piece 
)
inlinestatic

◆ _pipe_needs_gui_sampling_traversal()

◆ _pipe_tracks_gui_observables()

◆ _resync_global_histograms()

static gboolean _resync_global_histograms ( dt_dev_pixelpipe_t pipe,
dt_develop_t dev 
)
static

Re-sync the global histogram cache references on a pure cache hit.

Returns
TRUE if all required cache lines exist, FALSE if a recompute is needed.

A GUI-observable pipe can exit early if the final output cache entry is valid. When that happens, we still need to update the global histogram backbuffers to point at the right cache entries for demosaic/colorout/gamma. Realtime mode explicitly skips this path to avoid histogram sampling overhead.

If any required cache line is missing, we return FALSE so the caller recomputes the pipeline.

References _get_backuf(), _pipe_tracks_gui_observables(), darktable, dt_dev_pixelpipe_iop_t::data, dt_dev_pixelpipe_cache_peek(), dt_dev_pixelpipe_get_realtime(), dt_dev_pixelpipe_iop_t::enabled, dt_dev_pixelpipe_iop_t::global_hash, dt_dev_pixelpipe_t::nodes, darktable_t::pixelpipe_cache, pixelpipe_get_histogram_backbuf(), dt_dev_pixelpipe_iop_t::planned_roi_in, and dt_dev_pixelpipe_iop_t::planned_roi_out.

Referenced by dt_dev_pixelpipe_process().

◆ _sample_color_picker()

◆ _sample_gui()

static void _sample_gui ( dt_dev_pixelpipe_t pipe,
dt_develop_t dev,
void input,
void **  output,
const dt_iop_roi_t  roi_in,
const dt_iop_roi_t  roi_out,
dt_iop_buffer_dsc_t input_format,
dt_iop_buffer_dsc_t **  output_format,
dt_iop_module_t module,
dt_dev_pixelpipe_iop_t piece,
const uint64_t  input_hash,
const uint64_t  hash,
const size_t  in_bpp,
const size_t  bpp,
dt_pixel_cache_entry_t *const  input_entry,
dt_pixel_cache_entry_t *const  output_entry 
)
static

Sample all GUI observables for a processed module node.

This function is called after a module was processed and its input/output are available in the cache.

It performs:

  • global histogram cache reference update (raw/output/display),
  • per-module histogram computation,
  • color picker sampling for the active module (if enabled).

It locks the relevant cache entries for reading while sampling.

References _pipe_tracks_gui_observables(), _sample_color_picker(), bpp, collect_histogram_on_CPU(), darktable, dt_dev_pixelpipe_cache_rdlock_entry(), dt_dev_pixelpipe_get_realtime(), DT_PIXELPIPE_CACHE_HASH_INVALID, FALSE, dt_iop_module_t::op, output_format(), darktable_t::pixelpipe_cache, pixelpipe_get_histogram_backbuf(), TRUE, and void().

Referenced by dt_dev_pixelpipe_process_rec().

◆ _sync_module_output_backbuf_on_exact_hit()

static void _sync_module_output_backbuf_on_exact_hit ( dt_dev_pixelpipe_t pipe,
dt_develop_t dev,
dt_iop_module_t module,
dt_dev_pixelpipe_iop_t piece,
dt_pixel_cache_entry_t output_entry,
const dt_iop_roi_t  roi_out,
const uint64_t  hash 
)
static

◆ _transform_for_picker()

static dt_iop_colorspace_type_t _transform_for_picker ( dt_iop_module_t self,
const dt_iop_colorspace_type_t  cst 
)
static

Select a safe colorspace for picker sampling.

Some modules operate in RAW or specialized spaces. The picker wants meaningful values in an RGB-like space. This helper maps the active picker colorspace request to a safe in-pipe colorspace, falling back to the pipe colorspace when needed.

References dt_iop_color_picker_get_active_cst(), IOP_CS_HSL, IOP_CS_JZCZHZ, IOP_CS_LAB, IOP_CS_NONE, and IOP_CS_RGB.

Referenced by _sample_color_picker().

◆ collect_histogram_on_CPU()

static void collect_histogram_on_CPU ( dt_dev_pixelpipe_t pipe,
dt_develop_t dev,
float *  input,
const dt_iop_roi_t  roi_in,
dt_iop_buffer_dsc_t input_format,
dt_iop_module_t module,
dt_dev_pixelpipe_iop_t piece 
)
static

Collect the per-module histogram on CPU for GUI display.

This is gated by:

  • GUI state (attached) and module request flags,
  • histogram request mode (DT_REQUEST_ONLY_IN_GUI),
  • and per-module histogram enable flag.

The histogram is stored both in the piece (for internal use) and optionally copied to the module (for UI).

References dt_dev_histogram_stats_t::bins_count, dt_iop_buffer_dsc_t::cst, dt_control_queue_redraw_widget(), dt_ioppr_get_pipe_work_profile_info(), dt_ioppr_transform_image_colorspace(), DT_REQUEST_ON, DT_REQUEST_ONLY_IN_GUI, dt_develop_t::gui_attached, dt_iop_roi_t::height, dt_iop_module_t::histogram, dt_dev_pixelpipe_iop_t::histogram, histogram_collect(), dt_iop_module_t::histogram_max, dt_dev_pixelpipe_iop_t::histogram_max, dt_dev_pixelpipe_iop_t::histogram_stats, IOP_CS_RAW, dt_iop_module_t::request_histogram, dt_dev_pixelpipe_iop_t::request_histogram, dt_iop_module_t::widget, and dt_iop_roi_t::width.

Referenced by _sample_gui().

◆ histogram_collect()

static void histogram_collect ( dt_dev_pixelpipe_iop_t piece,
const void pixel,
const dt_iop_roi_t  roi,
uint32_t **  histogram,
uint32_t *  histogram_max 
)
static

Compute a histogram for a given module piece.

This is the per-module histogram that can be shown in module UIs. Each module may set piece->histogram_params to define a ROI. If no ROI is specified, we use the full ROI.

References dt_histogram_helper(), dt_histogram_max_helper(), dt_ioppr_get_pipe_work_profile_info(), dt_iop_roi_t::height, dt_dev_pixelpipe_iop_t::histogram_params, dt_dev_pixelpipe_iop_t::histogram_stats, dt_dev_pixelpipe_iop_t::pipe, dt_dev_histogram_collection_params_t::roi, dt_histogram_roi_t::width, and dt_iop_roi_t::width.

Referenced by collect_histogram_on_CPU().

◆ pixelpipe_get_histogram_backbuf()

static void pixelpipe_get_histogram_backbuf ( dt_develop_t dev,
const dt_iop_roi_t  roi,
dt_pixel_cache_entry_t entry,
dt_iop_module_t module,
const uint64_t  hash 
)
static

Update the global histogram backbuffer to reference a specific cache entry.

Global histograms are displayed outside of the pixelpipe processing call stack, so we must keep a cache reference (refcount increment) to prevent eviction of the buffer being displayed.

When the hash changes, we decrement the refcount of the previous entry and increment the refcount of the new one.

References _get_backuf(), bpp, darktable, dt_dev_backbuf_get_hash(), dt_dev_pixelpipe_cache_peek(), dt_dev_pixelpipe_cache_ref_count_entry(), dt_dev_set_backbuf(), dt_pixel_cache_entry_get_size(), DT_PIXELPIPE_CACHE_HASH_INVALID, FALSE, dt_iop_roi_t::height, dt_iop_module_t::op, darktable_t::pixelpipe_cache, TRUE, and dt_iop_roi_t::width.

Referenced by _resync_global_histograms(), _sample_gui(), and _sync_module_output_backbuf_on_exact_hit().

◆ pixelpipe_picker()

static void pixelpipe_picker ( dt_iop_module_t module,
dt_dev_pixelpipe_iop_t piece,
dt_iop_buffer_dsc_t dsc,
const float *  pixel,
const dt_iop_roi_t  roi,
float *  picked_color,
float *  picked_color_min,
float *  picked_color_max,
const dt_iop_colorspace_type_t  image_cst,
dt_pixelpipe_picker_source_t  picker_source 
)
static

Sample the color picker values (avg/min/max) from a pixel buffer.

The picker expects float buffers with known colorspace metadata. This function delegates the pixel aggregation to dt_color_picker_helper().

References dt_color_picker_helper(), dt_iop_color_picker_get_active_cst(), dt_ioppr_get_pipe_work_profile_info(), max, min, dt_dev_pixelpipe_iop_t::pipe, and pixelpipe_picker_helper().

Referenced by _sample_color_picker().

◆ pixelpipe_picker_helper()

static int pixelpipe_picker_helper ( dt_iop_module_t module,
const dt_iop_roi_t  roi,
dt_aligned_pixel_t  picked_color,
dt_aligned_pixel_t  picked_color_min,
dt_aligned_pixel_t  picked_color_max,
dt_pixelpipe_picker_source_t  picker_source,
int *  box 
)
static

Compute the sampling box in module coordinates for the interactive color picker.

Returns
0 on success, 1 if sampling should not happen (box outside ROI / invalid).

The GUI defines picker samples in normalized preview coordinates. We must convert them to pixel coordinates, then backtransform them to the current module coordinate system.

References dt_colorpicker_sample_t::box, dt_lib_t::colorpicker, darktable, darktable_t::develop, dt_dev_coordinates_image_norm_to_preview_abs(), dt_dev_distort_backtransform_plus(), DT_DEV_TRANSFORM_DIR_FORW_EXCL, DT_DEV_TRANSFORM_DIR_FORW_INCL, DT_LIB_COLORPICKER_SIZE_BOX, DT_LIB_COLORPICKER_SIZE_POINT, dt_develop_t::gui_module, height, dt_iop_roi_t::height, dt_iop_module_t::iop_order, darktable_t::lib, MAX, MIN, PIXELPIPE_PICKER_INPUT, dt_colorpicker_sample_t::point, dt_develop_t::preview_pipe, dt_lib_t::primary_sample, dt_lib_t::proxy, dt_colorpicker_sample_t::size, width, dt_iop_roi_t::width, dt_iop_roi_t::x, and dt_iop_roi_t::y.

Referenced by pixelpipe_picker().