Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
conversion.c File Reference
#include "colorprofiles/conversion.h"
#include "colorprofiles/colorspaces.h"
#include "colorprofiles/iop_profile.h"
#include "common/colorspaces_inline_conversions.h"
#include "common/logging.h"
#include "system/macros.h"
#include "system/mem_alloc.h"
#include "system/openmp.h"
#include "system/simd.h"
#include "system/target_clones.h"
#include <lcms2.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
+ Include dependency graph for conversion.c:

Go to the source code of this file.

Data Structures

struct  dt_colorspaces_conversion_t
 

Functions

static cmsHPROFILE _quantise_profile (cmsHPROFILE profile)
 
static cmsHPROFILE _resolve_endpoint (const dt_colorspaces_endpoint_t *const endpoint, const dt_colorspaces_color_profile_t **entry)
 
static cmsUInt32Number _format_for (cmsHPROFILE profile, gboolean *supported)
 
static gboolean _allocate_curves (float *lut[3])
 
static void _free_curves (float *lut[3])
 
dt_colorspaces_conversion_tdt_colorspaces_prepare_conversion (const dt_colorspaces_endpoint_t *const from, const dt_colorspaces_endpoint_t *const to, const dt_colorspaces_endpoint_t *const clip, const dt_colorspaces_endpoint_t *const proof, const dt_iop_color_intent_t intent, const dt_colorspaces_conversion_flags_t flags)
 Build a conversion from from to to. The expensive call; do it once.
 
void dt_colorspaces_free_conversion (dt_colorspaces_conversion_t **conversion)
 Release a conversion and NULL the caller's pointer.
 
static __attribute__ ((always_inline))
 
static __DT_CLONE_TARGETS__ void _apply_target_curves (const dt_colorspaces_conversion_t *const c, float *const restrict out, const size_t npixels)
 
static __DT_CLONE_TARGETS__ void _apply_matrix (const dt_colorspaces_conversion_t *const c, const float *const restrict in, float *const restrict out, const size_t npixels, const dt_colorspaces_conversion_hook_t hook)
 
static __DT_CLONE_TARGETS__ void _apply_lcms2 (const dt_colorspaces_conversion_t *const c, const float *const in, float *const out, const size_t width, const size_t height, const dt_colorspaces_conversion_hook_t hook)
 
void dt_colorspaces_apply_conversion_hooked (const dt_colorspaces_conversion_t *const conversion, const float *const in, float *const out, const size_t width, const size_t height, const dt_colorspaces_conversion_hook_t hook)
 dt_colorspaces_apply_conversion() with a per-pixel hook. See dt_colorspaces_conversion_hook_t for why this exists and why it should stay at one caller.
 
void dt_colorspaces_apply_conversion (const dt_colorspaces_conversion_t *const conversion, const float *const in, float *const out, const size_t width, const size_t height)
 Convert a 4-channel float image through a prepared conversion.
 
gboolean dt_colorspaces_conversion_is_matrix (const dt_colorspaces_conversion_t *const conversion)
 Whether the conversion reduced to matrices and curves, and can therefore be run by a device kernel at all.
 
gboolean dt_colorspaces_conversion_has_clipping (const dt_colorspaces_conversion_t *const conversion)
 Whether the conversion has a gamut-clipping stage, i.e. whether a clip endpoint was given AND survived preparation. Selects between a caller's clipping and non-clipping kernels.
 
gboolean dt_colorspaces_conversion_matrix (const dt_colorspaces_conversion_t *const conversion, dt_colormatrix_t matrix)
 The composed source-to-target matrix, row-major.
 
gboolean dt_colorspaces_conversion_source_matrix (const dt_colorspaces_conversion_t *const conversion, dt_colormatrix_t matrix)
 The SOURCE profile's own RGB -> XYZ (D50) matrix, before composition.
 
gboolean dt_colorspaces_conversion_clip_matrix (const dt_colorspaces_conversion_t *const conversion, dt_colormatrix_t matrix)
 The clip-to-target matrix, the second leg of a clipping conversion.
 
const float * dt_colorspaces_conversion_source_curve (const dt_colorspaces_conversion_t *const conversion, const int channel)
 One channel of the source decoding curves, DT_CONVERSION_LUT_SAMPLES entries.
 
const float * dt_colorspaces_conversion_target_curve (const dt_colorspaces_conversion_t *const conversion, const int channel)
 One channel of the target encoding curves. Same contract as dt_colorspaces_conversion_source_curve().
 
const float * dt_colorspaces_conversion_source_coeffs (const dt_colorspaces_conversion_t *const conversion)
 The 3x3 power-law fits extrapolating the source curves past white, as one flat array of 9 floats in channel-major order – the layout the kernels upload verbatim.
 
const float * dt_colorspaces_conversion_target_coeffs (const dt_colorspaces_conversion_t *const conversion)
 The same fits for the target curves. Same contract.
 

Function Documentation

◆ __attribute__()

static __attribute__ ( (always_inline )
inlinestatic

Definition at line 396 of file conversion.c.

References L, and v.

◆ _allocate_curves()

static gboolean _allocate_curves ( float *  lut[3])
static

◆ _apply_lcms2()

static __DT_CLONE_TARGETS__ void _apply_lcms2 ( const dt_colorspaces_conversion_t *const  c,
const float *const  in,
float *const  out,
const size_t  width,
const size_t  height,
const dt_colorspaces_conversion_hook_t  hook 
)
static

◆ _apply_matrix()

◆ _apply_target_curves()

static __DT_CLONE_TARGETS__ void _apply_target_curves ( const dt_colorspaces_conversion_t *const  c,
float *const restrict  out,
const size_t  npixels 
)
static

Definition at line 406 of file conversion.c.

References __OMP_PARALLEL_FOR__, DT_CONVERSION_LUT_SAMPLES, k, L, and out.

Referenced by _apply_matrix().

◆ _format_for()

static cmsUInt32Number _format_for ( cmsHPROFILE  profile,
gboolean *  supported 
)
static

◆ _free_curves()

static void _free_curves ( float *  lut[3])
static

Definition at line 164 of file conversion.c.

References dt_free_align, L, and lut.

Referenced by dt_colorspaces_free_conversion(), and dt_colorspaces_prepare_conversion().

◆ _quantise_profile()

static cmsHPROFILE _quantise_profile ( cmsHPROFILE  profile)
static

Definition at line 90 of file conversion.c.

References dt_free, IS_NULL_PTR, L, and size.

Referenced by dt_colorspaces_prepare_conversion().

◆ _resolve_endpoint()

static cmsHPROFILE _resolve_endpoint ( const dt_colorspaces_endpoint_t *const  endpoint,
const dt_colorspaces_color_profile_t **  entry 
)
static

◆ dt_colorspaces_apply_conversion()

void dt_colorspaces_apply_conversion ( const dt_colorspaces_conversion_t *const  conversion,
const float *const  in,
float *const  out,
const size_t  width,
const size_t  height 
)

Convert a 4-channel float image through a prepared conversion.

THE apply entry point. Runs whichever branch dt_colorspaces_prepare_conversion() settled on, over the whole buffer, parallelised. The 4th channel is not colour data and is not preserved – the matrix zeroes it and lcms2 leaves it undefined – which is why callers that carry a mask in it copy it back afterwards (dt_iop_alpha_copy()).

Parameters
conversionprepared conversion. NULL is a no-op, leaving out untouched.
insource, 4 floats per pixel, 16-byte aligned.
outdestination, same layout. Must NOT alias in: the matrix branch uses non-temporal stores, and the clipping and curve stages read a pixel after writing earlier ones.
widthpixels per row.
heightrows.

Definition at line 616 of file conversion.c.

References dt_colorspaces_apply_conversion_hooked(), height, L, out, and width.

Referenced by process().

◆ dt_colorspaces_apply_conversion_hooked()

void dt_colorspaces_apply_conversion_hooked ( const dt_colorspaces_conversion_t *const  conversion,
const float *const  in,
float *const  out,
const size_t  width,
const size_t  height,
const dt_colorspaces_conversion_hook_t  hook 
)

dt_colorspaces_apply_conversion() with a per-pixel hook. See dt_colorspaces_conversion_hook_t for why this exists and why it should stay at one caller.

Parameters
hookapplied to every pixel between decoding and conversion. NULL is exactly dt_colorspaces_apply_conversion().

Definition at line 604 of file conversion.c.

References _apply_lcms2(), _apply_matrix(), height, dt_colorspaces_conversion_t::is_matrix, IS_NULL_PTR, L, out, and width.

Referenced by dt_colorspaces_apply_conversion(), and process().

◆ dt_colorspaces_conversion_clip_matrix()

gboolean dt_colorspaces_conversion_clip_matrix ( const dt_colorspaces_conversion_t *const  conversion,
dt_colormatrix_t  matrix 
)

The clip-to-target matrix, the second leg of a clipping conversion.

Parameters
matrixfilled with the matrix. Untouched, and FALSE returned, when the conversion has no clipping stage.
Returns
TRUE when matrix was written.

Definition at line 650 of file conversion.c.

References dt_colorspaces_conversion_t::clip_matrix, FALSE, dt_colorspaces_conversion_t::has_clipping, dt_colorspaces_conversion_t::is_matrix, IS_NULL_PTR, L, matrix, and TRUE.

Referenced by process_cl().

◆ dt_colorspaces_conversion_has_clipping()

gboolean dt_colorspaces_conversion_has_clipping ( const dt_colorspaces_conversion_t *const  conversion)

Whether the conversion has a gamut-clipping stage, i.e. whether a clip endpoint was given AND survived preparation. Selects between a caller's clipping and non-clipping kernels.

Definition at line 629 of file conversion.c.

References dt_colorspaces_conversion_t::has_clipping, and IS_NULL_PTR.

Referenced by process_cl().

◆ dt_colorspaces_conversion_is_matrix()

gboolean dt_colorspaces_conversion_is_matrix ( const dt_colorspaces_conversion_t *const  conversion)

Whether the conversion reduced to matrices and curves, and can therefore be run by a device kernel at all.

Returns
TRUE for the matrix branch, FALSE for the lcms2 fallback (which is host-only, so the caller must clear piece->process_cl_ready). FALSE for a NULL conversion.

Definition at line 624 of file conversion.c.

References dt_colorspaces_conversion_t::is_matrix, and IS_NULL_PTR.

Referenced by commit_params().

◆ dt_colorspaces_conversion_matrix()

gboolean dt_colorspaces_conversion_matrix ( const dt_colorspaces_conversion_t *const  conversion,
dt_colormatrix_t  matrix 
)

The composed source-to-target matrix, row-major.

With a clipping stage this is the source-to-CLIP matrix, and dt_colorspaces_conversion_clip_matrix() is the second leg – which is the argument pair the colorin_clipping kernel already takes.

Parameters
matrixfilled with the matrix. Left untouched, and FALSE returned, on the lcms2 branch or for a NULL conversion.
Returns
TRUE when matrix was written.

Definition at line 634 of file conversion.c.

References FALSE, dt_colorspaces_conversion_t::is_matrix, IS_NULL_PTR, L, dt_colorspaces_conversion_t::matrix, matrix, and TRUE.

Referenced by process_cl().

◆ dt_colorspaces_conversion_source_coeffs()

const float * dt_colorspaces_conversion_source_coeffs ( const dt_colorspaces_conversion_t *const  conversion)

The 3x3 power-law fits extrapolating the source curves past white, as one flat array of 9 floats in channel-major order – the layout the kernels upload verbatim.

Returns
The coefficients, or NULL when the conversion has no source curve stage.
See also
dt_ioppr_eval_trc(), which is what evaluates them.

Definition at line 672 of file conversion.c.

References dt_colorspaces_conversion_t::coeffs_source, IS_NULL_PTR, L, and dt_colorspaces_conversion_t::lut_source.

Referenced by process_cl().

◆ dt_colorspaces_conversion_source_curve()

const float * dt_colorspaces_conversion_source_curve ( const dt_colorspaces_conversion_t *const  conversion,
const int  channel 
)

One channel of the source decoding curves, DT_CONVERSION_LUT_SAMPLES entries.

Parameters
channel0, 1 or 2.
Returns
The curve, or NULL on the lcms2 branch or when DT_CONVERSION_SOURCE_CURVES was not asked for. Present-but-linear is NOT reported as NULL: a curve whose first entry is negative marks that channel linear, which is the convention both the CPU path and the kernels read, so a caller that declared it consumes this side always gets a buffer it can upload. Valid for the life of the conversion.

Definition at line 658 of file conversion.c.

References IS_NULL_PTR, L, and dt_colorspaces_conversion_t::lut_source.

Referenced by process_cl().

◆ dt_colorspaces_conversion_source_matrix()

gboolean dt_colorspaces_conversion_source_matrix ( const dt_colorspaces_conversion_t *const  conversion,
dt_colormatrix_t  matrix 
)

The SOURCE profile's own RGB -> XYZ (D50) matrix, before composition.

Not for converting anything – for describing the source space to something else. iop/colorin.c hands it to the pipe as part of the input-profile record, which downstream modules read to know what the buffer they receive is in.

Parameters
matrixfilled with the matrix. Untouched, and FALSE returned, when the source profile does not reduce to a colorant matrix (a CLUT profile, say), which is the same answer as "there is no such matrix to report".
Returns
TRUE when matrix was written. Available on both branches: a conversion that runs through lcms2 can still have a perfectly good source matrix, and the reason it fell back may have been the target profile.

Definition at line 642 of file conversion.c.

References FALSE, dt_colorspaces_conversion_t::have_source_matrix, IS_NULL_PTR, L, matrix, dt_colorspaces_conversion_t::source_matrix, and TRUE.

Referenced by commit_params().

◆ dt_colorspaces_conversion_target_coeffs()

const float * dt_colorspaces_conversion_target_coeffs ( const dt_colorspaces_conversion_t *const  conversion)

The same fits for the target curves. Same contract.

Definition at line 678 of file conversion.c.

References dt_colorspaces_conversion_t::coeffs_target, IS_NULL_PTR, L, and dt_colorspaces_conversion_t::lut_target.

Referenced by process_cl().

◆ dt_colorspaces_conversion_target_curve()

const float * dt_colorspaces_conversion_target_curve ( const dt_colorspaces_conversion_t *const  conversion,
const int  channel 
)

One channel of the target encoding curves. Same contract as dt_colorspaces_conversion_source_curve().

Definition at line 665 of file conversion.c.

References IS_NULL_PTR, L, and dt_colorspaces_conversion_t::lut_target.

Referenced by process_cl().

◆ dt_colorspaces_free_conversion()

void dt_colorspaces_free_conversion ( dt_colorspaces_conversion_t **  conversion)

Release a conversion and NULL the caller's pointer.

Parameters
conversionaddress OF the caller's pointer. A NULL address, or an address holding NULL, is a no-op. Closes whichever profile handles the conversion owns (never the borrowed ones) and deletes its transform.

Definition at line 377 of file conversion.c.

References _free_curves(), dt_colorspaces_cleanup_profile(), IS_NULL_PTR, k, and L.

Referenced by cleanup_pipe(), commit_params(), and dt_colorspaces_prepare_conversion().

◆ dt_colorspaces_prepare_conversion()

Build a conversion from from to to. The expensive call; do it once.

Resolves both endpoints (holding each profile's own lock across the derivation, because the display profile's handle is replaced on a monitor change), then decides the branch: if neither soft-proofing nor DT_CONVERSION_FORCE_LCMS2 is asked for, and both profiles reduce to a colorant matrix, and every curve stage the profiles need is one the caller declared it can run, the result is a composed matrix plus at most two curve sets. Otherwise it is a cmsHTRANSFORM. Either way dt_colorspaces_apply_conversion() runs it.

Parameters
fromsource space. Must not be NULL.
totarget space. Must not be NULL.
clipoptional third space whose primaries bound the result: the conversion becomes source -> clip, clamp each channel to [0,1], clip -> target. Only the primaries are used, never the tone curves – this is a gamut clamp, not a round trip. NULL for the ordinary direct conversion.
proofoptional soft-proof space. Non-NULL builds a proofing transform with black point compensation, which always means the lcms2 branch. The profile is quantised first (several built-ins carry a parametric TRC that lcms2 would round-trip exactly, making the proof a no-op); if that quantisation fails, proofing is silently dropped and an ordinary transform is built, which is the pre-existing behaviour.
intentrendering intent for the lcms2 branch. The matrix branch has no intent.
flagssee dt_colorspaces_conversion_flags_t.
Returns
A new conversion, or NULL if neither branch could be built (both endpoints unresolvable, or cmsCreateTransform refused the pair). Release it with dt_colorspaces_free_conversion().
Note
Never call this from process(). It costs two 65536-entry curve extractions on the matrix branch and 2.2-38 ms on the lcms2 one.

Definition at line 173 of file conversion.c.

References _allocate_curves(), _format_for(), _free_curves(), _quantise_profile(), _resolve_endpoint(), dt_colorspaces_conversion_t::clip_matrix, dt_colorspaces_conversion_t::clip_xform, dt_colorspaces_conversion_t::coeffs_source, dt_colorspaces_conversion_t::coeffs_target, dt_colormatrix_mul(), dt_colorspaces_free_conversion(), dt_colorspaces_get_matrix_from_input_profile(), dt_colorspaces_get_matrix_from_output_profile(), dt_colorspaces_lock_profile(), dt_colorspaces_unlock_profile(), DT_CONVERSION_FORCE_LCMS2, DT_CONVERSION_GAMUTCHECK, DT_CONVERSION_LUT_SAMPLES, DT_CONVERSION_SOURCE_CURVES, DT_CONVERSION_TARGET_CURVES, dt_ioppr_init_unbounded_coeffs(), FALSE, flags, dt_colorspaces_conversion_t::from_type, dt_colorspaces_conversion_t::gamutcheck, dt_colorspaces_conversion_t::has_clipping, dt_colorspaces_conversion_t::have_source_matrix, dt_colorspaces_conversion_t::is_matrix, IS_NULL_PTR, L, dt_colorspaces_conversion_t::lut_source, dt_colorspaces_conversion_t::lut_target, dt_colorspaces_conversion_t::matrix, dt_colorspaces_conversion_t::n_owned, dt_colorspaces_conversion_t::nonlinear_source, dt_colorspaces_conversion_t::nonlinear_target, dt_colorspaces_conversion_t::owned, dt_colorspaces_conversion_t::source_matrix, dt_colorspaces_conversion_t::to_type, TRUE, and dt_colorspaces_conversion_t::xform.

Referenced by commit_params().