![]() |
Ansel 0.0
A darktable fork - bloat + design vision
|
#include "colorprofiles/conversion.h"#include "colorprofiles/colorspaces.h"#include "colorprofiles/iop_profile.h"#include "common/colorspaces_inline_conversions.h"#include "common/hash.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 |
Macros | |
| #define | DT_CONVERSION_MAGIC_LIVE 0xC0117E51u |
| #define | DT_CONVERSION_MAGIC_DEAD 0xDEADC017u |
| #define DT_CONVERSION_MAGIC_DEAD 0xDEADC017u |
Definition at line 56 of file conversion.c.
| #define DT_CONVERSION_MAGIC_LIVE 0xC0117E51u |
The prepared conversion. Two shapes live in here, and exactly one of them is active:
is_matrix == TRUE source curves -> matrix -> [clamp in clip primaries -> matrix] -> target curves is_matrix == FALSE one or two cmsHTRANSFORM, with the clamp between them when the conversion clips.
The sentinel encodings the two IOPs used to dispatch on from the outside – isnan(m[0][0]) for "no matrix", lut[c][0] < 0 for "this channel is linear" – are still how the curves are stored, because that is what dt_ioppr_eval_trc() and the OpenCL kernels read. The difference is that they are now read here and by the kernels, not by module logic.
Definition at line 55 of file conversion.c.
|
inlinestatic |
Definition at line 536 of file conversion.c.
|
static |
Definition at line 196 of file conversion.c.
References dt_alloc_align_float(), DT_CONVERSION_LUT_SAMPLES, FALSE, IS_NULL_PTR, lut, and TRUE.
Referenced by dt_colorspaces_prepare_conversion().
|
static |
Definition at line 685 of file conversion.c.
References __OMP_PARALLEL_FOR__, __OMP_SIMD__, ch, dt_colorspaces_transform_rgba_float_row(), height, IS_NULL_PTR, L, out, row, and width.
Referenced by dt_colorspaces_apply_conversion_hooked().
|
static |
Definition at line 593 of file conversion.c.
References __OMP_PARALLEL_FOR__, __OMP_PARALLEL_FOR_SIMD__, _apply_target_curves(), c1, c2, DT_CONVERSION_LUT_SAMPLES, dt_omploop_sfence, dt_store_simd_aligned(), IS_NULL_PTR, k, L, m, out, transpose_3xSSE(), and v.
Referenced by dt_colorspaces_apply_conversion_hooked().
|
static |
Definition at line 546 of file conversion.c.
References __OMP_PARALLEL_FOR__, DT_CONVERSION_LUT_SAMPLES, k, L, and out.
Referenced by _apply_matrix().
|
static |
Is this pointer a live conversion?
NULL is an ordinary, quiet "no conversion" – every accessor already treated it that way. A dead tag is a use-after-free caught while the page is still mapped; anything else is a pointer that never was a conversion (issues #1212/#1216 observed the module's conversion field clobbered with a foreign pointer mid-commit). Both are reported by address so the next field report carries the value instead of a signal name.
Definition at line 489 of file conversion.c.
References DT_CONVERSION_MAGIC_DEAD, DT_CONVERSION_MAGIC_LIVE, DT_DEBUG_ALWAYS, dt_print(), FALSE, IS_NULL_PTR, L, dt_colorspaces_conversion_t::magic, and TRUE.
Referenced by dt_colorspaces_apply_conversion_hooked(), dt_colorspaces_conversion_clip_matrix(), dt_colorspaces_conversion_has_clipping(), dt_colorspaces_conversion_identity(), dt_colorspaces_conversion_is_matrix(), dt_colorspaces_conversion_matrix(), dt_colorspaces_conversion_source_coeffs(), dt_colorspaces_conversion_source_curve(), dt_colorspaces_conversion_source_matrix(), dt_colorspaces_conversion_target_coeffs(), dt_colorspaces_conversion_target_curve(), and dt_colorspaces_free_conversion().
|
static |
Definition at line 175 of file conversion.c.
References DT_DEBUG_COLORPROFILE, dt_print(), FALSE, IS_NULL_PTR, L, supported(), TRUE, and TYPE_XYZA_FLT.
Referenced by dt_colorspaces_prepare_conversion().
Definition at line 207 of file conversion.c.
References dt_free_align, L, and lut.
Referenced by dt_colorspaces_free_conversion(), and dt_colorspaces_prepare_conversion().
|
static |
Definition at line 151 of file conversion.c.
References DT_COLORSPACE_NONE, dt_hash(), dt_colorspaces_color_profile_t::filename, hash, IS_NULL_PTR, L, dt_colorspaces_color_profile_t::type, and type.
Referenced by dt_colorspaces_prepare_conversion().
|
static |
Definition at line 104 of file conversion.c.
References dt_free, IS_NULL_PTR, L, and size.
Referenced by dt_colorspaces_prepare_conversion().
|
static |
Definition at line 126 of file conversion.c.
References dt_colorspaces_get_profile(), IS_NULL_PTR, L, and dt_colorspaces_color_profile_t::profile.
Referenced by dt_colorspaces_prepare_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()).
| conversion | prepared conversion. NULL is a no-op, leaving out untouched. |
| in | source, 4 floats per pixel, 16-byte aligned. |
| out | destination, 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. |
| width | pixels per row. |
| height | rows. |
Definition at line 762 of file conversion.c.
References dt_colorspaces_apply_conversion_hooked(), height, L, out, and width.
Referenced by process().
| 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.
| hook | applied to every pixel between decoding and conversion. NULL is exactly dt_colorspaces_apply_conversion(). |
Definition at line 744 of file conversion.c.
References _apply_lcms2(), _apply_matrix(), _conversion_valid(), height, dt_colorspaces_conversion_t::is_matrix, IS_NULL_PTR, L, out, and width.
Referenced by dt_colorspaces_apply_conversion(), and process().
| 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.
| matrix | filled with the matrix. Untouched, and FALSE returned, when the conversion has no clipping stage. |
matrix was written. Definition at line 796 of file conversion.c.
References _conversion_valid(), dt_colorspaces_conversion_t::clip_matrix, FALSE, dt_colorspaces_conversion_t::has_clipping, dt_colorspaces_conversion_t::is_matrix, L, matrix, and TRUE.
Referenced by process_cl().
| 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 775 of file conversion.c.
References _conversion_valid(), and dt_colorspaces_conversion_t::has_clipping.
Referenced by process_cl().
| uint64_t dt_colorspaces_conversion_identity | ( | const dt_colorspaces_conversion_t *const | conversion | ) |
What this conversion IS, as a number: equal for two conversions that render the same pixels, different otherwise.
For a caller that folds its rendering state into a pipeline cache key. The prepared conversion is opaque and lives on the heap, so a caller holding one has nothing else to offer a hash but its ADDRESS – and an address describes no pixels. It both MISSES (the allocator hands back a different address for an identical conversion, re-keying the whole downstream chain to recompute pixels that cannot have moved) and, worse, HITS FALSELY (it hands back the SAME address for a conversion built from a different profile or intent, and the cache serves the previous one's pixels under the new key).
This is the fix for both: it names the profiles the conversion resolved to, the intent and flags it was built with, the shape it settled on, its matrices, and the colour-management settings generation – which is what separates two monitor profiles, since both are called DT_COLORSPACE_DISPLAY and differ only in their bytes.
Definition at line 503 of file conversion.c.
References _conversion_valid(), and dt_colorspaces_conversion_t::identity.
Referenced by commit_params().
| 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.
piece->process_cl_ready). FALSE for a NULL conversion. Definition at line 770 of file conversion.c.
References _conversion_valid(), and dt_colorspaces_conversion_t::is_matrix.
Referenced by commit_params().
| 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.
| matrix | filled with the matrix. Left untouched, and FALSE returned, on the lcms2 branch or for a NULL conversion. |
matrix was written. Definition at line 780 of file conversion.c.
References _conversion_valid(), FALSE, dt_colorspaces_conversion_t::is_matrix, L, dt_colorspaces_conversion_t::matrix, matrix, and TRUE.
Referenced by process_cl().
| 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.
Definition at line 818 of file conversion.c.
References _conversion_valid(), dt_colorspaces_conversion_t::coeffs_source, IS_NULL_PTR, L, and dt_colorspaces_conversion_t::lut_source.
Referenced by process_cl().
| 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.
| channel | 0, 1 or 2. |
Definition at line 804 of file conversion.c.
References _conversion_valid(), L, and dt_colorspaces_conversion_t::lut_source.
Referenced by process_cl().
| 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.
| matrix | filled 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". |
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 788 of file conversion.c.
References _conversion_valid(), FALSE, dt_colorspaces_conversion_t::have_source_matrix, L, matrix, dt_colorspaces_conversion_t::source_matrix, and TRUE.
Referenced by commit_params().
| 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 824 of file conversion.c.
References _conversion_valid(), dt_colorspaces_conversion_t::coeffs_target, IS_NULL_PTR, L, and dt_colorspaces_conversion_t::lut_target.
Referenced by process_cl().
| 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 811 of file conversion.c.
References _conversion_valid(), L, and dt_colorspaces_conversion_t::lut_target.
Referenced by process_cl().
| void dt_colorspaces_free_conversion | ( | dt_colorspaces_conversion_t ** | conversion | ) |
Release a conversion and NULL the caller's pointer.
| conversion | address 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 508 of file conversion.c.
References _conversion_valid(), _free_curves(), dt_colorspaces_cleanup_profile(), DT_CONVERSION_MAGIC_DEAD, dt_free_align, IS_NULL_PTR, k, and L.
Referenced by cleanup_pipe(), commit_params(), and dt_colorspaces_prepare_conversion().
| dt_colorspaces_conversion_t * dt_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.
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.
| from | source space. Must not be NULL. |
| to | target space. Must not be NULL. |
| clip | optional 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. |
| proof | optional 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. |
| intent | rendering intent for the lcms2 branch. The matrix branch has no intent. |
| flags | see dt_colorspaces_conversion_flags_t. |
cmsCreateTransform refused the pair). Release it with dt_colorspaces_free_conversion(). process(). It costs two 65536-entry curve extractions on the matrix branch and 2.2-38 ms on the lcms2 one. Definition at line 216 of file conversion.c.
References _allocate_curves(), _format_for(), _free_curves(), _hash_endpoint(), _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_calloc_align(), dt_colormatrix_mul(), dt_colorprofiles_get_settings(), 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_MAGIC_LIVE, DT_CONVERSION_SOURCE_CURVES, DT_CONVERSION_TARGET_CURVES, dt_hash(), 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::identity, 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::magic, 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().