Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
pixelpipe_cpu.c
Go to the documentation of this file.
1/*
2 Private CPU pixelpipe backend.
3*/
4
5#include "system/macros.h"
7#include "system/openmp.h"
8#include "common/logging.h"
10#include "develop/iop_order.h"
11#include "develop/blend.h"
13
14#include <assert.h>
15#include <math.h>
16#include <stdio.h>
17
19 const dt_dev_pixelpipe_iop_t *previous_piece,
21 gboolean *const cache_output,
22 dt_pixel_cache_entry_t *input_entry, dt_pixel_cache_entry_t *output_entry)
23{
24 dt_iop_module_t *module = piece->module;
25 float *input = input_entry ? dt_pixel_cache_entry_get_data(input_entry) : NULL;
26 void *output = dt_pixel_cache_entry_get_data(output_entry);
27 float *process_input_temp = NULL;
28 float *blend_input_temp = NULL;
29 float *blend_output_temp = NULL;
30 const float *process_input = input;
31 const float *blend_input = input;
32 void *blend_output = output;
33 const dt_iop_buffer_dsc_t actual_input_dsc = previous_piece ? previous_piece->dsc_out : pipe->dev->image_storage.dsc;
34 dt_iop_buffer_dsc_t process_input_dsc = actual_input_dsc;
35 dt_iop_buffer_dsc_t blend_input_dsc = actual_input_dsc;
36 dt_iop_buffer_dsc_t blend_output_dsc = piece->dsc_out;
37 gboolean input_locked = FALSE;
38
39 if(IS_NULL_PTR(input) && !(module->flags() & IOP_FLAGS_TAKE_NO_INPUT))
40 {
41 fprintf(stdout, "[dev_pixelpipe] %s got a NULL input, report that to developers\n", module->name());
42 return 1;
43 }
44 if(IS_NULL_PTR(output))
45 output = dt_pixel_cache_alloc(output_entry);
46
47 if(IS_NULL_PTR(output))
48 {
49 fprintf(stdout, "[dev_pixelpipe] %s got a NULL output, report that to developers\n", module->name());
50 return 1;
51 }
52
53 const dt_iop_order_iccprofile_info_t *const work_profile
54 = (process_input_dsc.cst != IOP_CS_RAW || piece->dsc_in.cst != IOP_CS_RAW)
56 : NULL;
57
58 const int cst_before = process_input_dsc.cst;
59 if(process_input_dsc.cst != piece->dsc_in.cst
60 && !(dt_iop_colorspace_is_rgb(process_input_dsc.cst) && dt_iop_colorspace_is_rgb(piece->dsc_in.cst)))
61 {
62 process_input_temp
63 = dt_pixelpipe_cache_alloc_align_float((size_t)piece->roi_in.width * piece->roi_in.height * 4, pipe);
64 if(IS_NULL_PTR(process_input_temp))
65 return 1;
66
68 input_locked = TRUE;
69 dt_colorspaces_apply_profile(module->op, module->multi_name, input, process_input_temp, piece->roi_in.width,
70 piece->roi_in.height, process_input_dsc.cst, piece->dsc_in.cst,
71 &process_input_dsc.cst, work_profile);
73 input_locked = FALSE;
74 process_input = process_input_temp;
75 }
76 else if(process_input_dsc.cst != piece->dsc_in.cst)
77 {
78 process_input_dsc.cst = piece->dsc_in.cst;
79 if(input_entry)
80 {
82 input_locked = TRUE;
83 }
84 }
85 else
86 {
87 if(input_entry)
88 {
90 input_locked = TRUE;
91 }
92 }
93 const int cst_after = process_input_dsc.cst;
94
95 dt_dev_pixelpipe_debug_dump_module_io(pipe, module, "pre", FALSE, &piece->dsc_in, &piece->dsc_out,
96 &piece->roi_in, &piece->roi_out,
97 process_input_dsc.bpp, piece->dsc_out.bpp, cst_before, cst_after);
98
99 if((dt_get_debug_flags() & DT_DEBUG_NAN) && !IS_NULL_PTR(output) && piece->dsc_out.datatype == TYPE_FLOAT)
100 {
101 const size_t ch = piece->dsc_out.channels;
102 const size_t count = (size_t)piece->roi_out.width * (size_t)piece->roi_out.height * ch;
103 float *out = (float *)output;
105 for(size_t k = 0; k < count; k++)
106 out[k] = NAN;
107 }
108
109 /* Asked only when the module can be tiled. The answer chooses between process() and
110 * process_tiling(), and getting it EVICTS cache lines -- other pipes' included -- until the
111 * module's whole working set fits one contiguous arena run. For a module that cannot be tiled
112 * it chooses nothing, process() runs either way, and the eviction only threw work away: a
113 * full-resolution tone equalizer in the preview pipe emptied most of the cache on every edit,
114 * and the FULL pipe then recomputed from its raw input. The module's own allocations still
115 * evict what each of them needs, when it is made. */
116 const gboolean fitting
117 = !piece->process_tiling_ready
119 MAX(piece->roi_in.height, piece->roi_out.height),
120 MAX(process_input_dsc.bpp, piece->dsc_out.bpp),
121 tiling->factor, tiling->overhead);
122
123 int err = 0;
124 if(!fitting && piece->process_tiling_ready)
125 {
126 err = module->process_tiling(module, pipe, piece, process_input, output, process_input_dsc.bpp);
128 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_PROCESSED_ON_GPU);
129 }
130 else
131 {
132 err = module->process(module, pipe, piece, process_input, output);
133 *pixelpipe_flow |= PIXELPIPE_FLOW_PROCESSED_ON_CPU;
135 }
136
137 if(err)
138 {
139 fprintf(stdout, "[pixelpipe] %s process on CPU returned with an error\n", module->name());
140 if(input_locked)
142 dt_pixelpipe_cache_free_align(process_input_temp);
143 return err;
144 }
145
146 if(module->flags() & IOP_FLAGS_SUPPORTS_BLENDING)
147 {
148 blend_input = process_input;
149 blend_input_dsc = process_input_dsc;
150 blend_output = output;
151 blend_output_dsc = piece->dsc_out;
152
153 const dt_pixelpipe_blend_transform_t blend_transforms
154 = dt_dev_pixelpipe_transform_for_blend(module, piece, &piece->dsc_out);
155 if(blend_transforms != DT_DEV_PIXELPIPE_BLEND_TRANSFORM_NONE)
156 {
158 const int blend_in_before = blend_input_dsc.cst;
159 if(blend_transforms & DT_DEV_PIXELPIPE_BLEND_TRANSFORM_INPUT)
160 {
161 blend_input_temp
162 = dt_pixelpipe_cache_alloc_align_float((size_t)piece->roi_in.width * piece->roi_in.height * 4, pipe);
163 if(IS_NULL_PTR(blend_input_temp))
164 {
165 if(input_locked)
167 dt_pixelpipe_cache_free_align(process_input_temp);
168 return 1;
169 }
170
171 dt_colorspaces_apply_profile(module->op, module->multi_name, process_input, blend_input_temp, piece->roi_in.width,
172 piece->roi_in.height, blend_input_dsc.cst, blend_cst,
173 &blend_input_dsc.cst, work_profile);
174 blend_input = blend_input_temp;
175 if(input_locked)
176 {
178 input_locked = FALSE;
179 }
180 }
181 const int blend_in_after = blend_input_dsc.cst;
182
183 dt_dev_pixelpipe_debug_dump_module_io(pipe, module, "blend-in", FALSE, &process_input_dsc, &blend_input_dsc,
184 &piece->roi_in, &piece->roi_in,
185 process_input_dsc.bpp, blend_input_dsc.bpp,
186 blend_in_before, blend_in_after);
187
188 const int blend_out_before = blend_output_dsc.cst;
189 if(blend_transforms & DT_DEV_PIXELPIPE_BLEND_TRANSFORM_OUTPUT)
190 {
191 blend_output_temp
192 = dt_pixelpipe_cache_alloc_align_float((size_t)piece->roi_out.width * piece->roi_out.height * 4, pipe);
193 if(IS_NULL_PTR(blend_output_temp))
194 {
195 if(input_locked)
197 dt_pixelpipe_cache_free_align(blend_input_temp);
198 dt_pixelpipe_cache_free_align(process_input_temp);
199 return 1;
200 }
201
202 dt_colorspaces_apply_profile(module->op, module->multi_name, output, blend_output_temp, piece->roi_out.width,
203 piece->roi_out.height, blend_output_dsc.cst, blend_cst,
204 &blend_output_dsc.cst, work_profile);
205 blend_output = blend_output_temp;
206 }
207 const int blend_out_after = blend_output_dsc.cst;
208
209 dt_dev_pixelpipe_debug_dump_module_io(pipe, module, "blend-out", FALSE, &piece->dsc_out, &blend_output_dsc,
210 &piece->roi_out, &piece->roi_out,
211 piece->dsc_out.bpp, blend_output_dsc.bpp,
212 blend_out_before, blend_out_after);
213 }
214
215 err = dt_develop_blend_process(module, pipe, piece, blend_input, blend_output);
216 *pixelpipe_flow |= PIXELPIPE_FLOW_BLENDED_ON_CPU;
217 *pixelpipe_flow &= ~(PIXELPIPE_FLOW_BLENDED_ON_GPU);
218
219 if(!err && (blend_transforms & DT_DEV_PIXELPIPE_BLEND_TRANSFORM_OUTPUT))
220 {
221 // A mask or channel preview is converted like any output: the preview is authored in the
222 // blending space precisely so this conversion lands it where the display expects it.
223 dt_colorspaces_apply_profile(module->op, module->multi_name, blend_output, output, piece->roi_out.width,
224 piece->roi_out.height, blend_output_dsc.cst, piece->dsc_out.cst,
225 &blend_output_dsc.cst, work_profile);
226 }
227 }
228
229 if(input_locked)
231 dt_pixelpipe_cache_free_align(blend_output_temp);
232 dt_pixelpipe_cache_free_align(blend_input_temp);
233 dt_pixelpipe_cache_free_align(process_input_temp);
234
235 return err;
236}
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
dt_iop_colorspace_type_t dt_develop_blend_colorspace(const dt_dev_pixelpipe_iop_t *const piece, dt_iop_colorspace_type_t cst)
Definition blend.c:234
int dt_develop_blend_process(struct dt_iop_module_t *self, dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid)
Definition blend.c:704
dt_iop_colorspace_type_t
@ IOP_CS_RAW
void dt_colorspaces_apply_profile(const char *const op_name, const char *const instance_name, const float *const image_in, float *const image_out, const int width, const int height, const int cst_from, const int cst_to, int *converted_cst, const dt_iop_order_iccprofile_info_t *const profile_info)
Convert a 4-channel float buffer between RGB and Lab through one profile.
const dt_colormatrix_t dt_aligned_pixel_t out
dt_iop_order_iccprofile_info_t * dt_ioppr_get_pipe_work_profile_info(const struct dt_dev_pixelpipe_t *pipe)
static gboolean dt_iop_colorspace_is_rgb(const dt_iop_colorspace_type_t cst)
Definition format.h:75
@ TYPE_FLOAT
Definition format.h:56
@ IOP_FLAGS_SUPPORTS_BLENDING
Definition imageop.h:186
@ IOP_FLAGS_TAKE_NO_INPUT
Definition imageop.h:195
@ DT_DEBUG_NAN
Definition logging.h:61
int32_t dt_get_debug_flags(void)
Definition darktable.c:2085
float *const restrict const size_t k
float *const restrict const size_t const size_t ch
#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 __OMP_PARALLEL_FOR_SIMD__(...)
Definition openmp.h:96
void * dt_pixel_cache_entry_get_data(dt_pixel_cache_entry_t *entry)
void dt_dev_pixelpipe_cache_rdlock_entry(gboolean lock, dt_pixel_cache_entry_t *cache_entry)
Lock or release the read lock on the entry.
void * dt_pixel_cache_alloc(dt_pixel_cache_entry_t *cache_entry)
Actually allocate the memory buffer attached to the cache entry once you create it with dt_dev_pixelp...
#define dt_pixelpipe_cache_free_align(mem)
#define dt_pixelpipe_cache_alloc_align_float(pixels, pipe)
int pixelpipe_process_on_CPU(dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *piece, const dt_dev_pixelpipe_iop_t *previous_piece, dt_develop_tiling_t *tiling, dt_pixelpipe_flow_t *pixelpipe_flow, gboolean *const cache_output, dt_pixel_cache_entry_t *input_entry, dt_pixel_cache_entry_t *output_entry)
dt_pixelpipe_blend_transform_t dt_dev_pixelpipe_transform_for_blend(const dt_iop_module_t *const self, const dt_dev_pixelpipe_iop_t *const piece, const dt_iop_buffer_dsc_t *const output_dsc)
void dt_dev_pixelpipe_debug_dump_module_io(dt_dev_pixelpipe_t *pipe, dt_iop_module_t *module, const char *stage, const gboolean is_cl, const dt_iop_buffer_dsc_t *in_dsc, const dt_iop_buffer_dsc_t *out_dsc, const dt_iop_roi_t *roi_in, const dt_iop_roi_t *roi_out, const size_t in_bpp, const size_t out_bpp, const int cst_before, const int cst_after)
dt_pixelpipe_flow_t
@ PIXELPIPE_FLOW_PROCESSED_ON_CPU
@ PIXELPIPE_FLOW_PROCESSED_WITH_TILING
@ PIXELPIPE_FLOW_PROCESSED_ON_GPU
@ PIXELPIPE_FLOW_BLENDED_ON_CPU
@ PIXELPIPE_FLOW_BLENDED_ON_GPU
dt_pixelpipe_blend_transform_t
@ DT_DEV_PIXELPIPE_BLEND_TRANSFORM_INPUT
@ DT_DEV_PIXELPIPE_BLEND_TRANSFORM_NONE
@ DT_DEV_PIXELPIPE_BLEND_TRANSFORM_OUTPUT
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
struct dt_develop_t * dev
dt_image_t image_storage
Definition develop.h:225
dt_iop_buffer_dsc_t dsc
Definition image.h:419
unsigned int channels
Definition format.h:83
dt_iop_buffer_type_t datatype
Definition format.h:85
A profile reduced to the arithmetic the pixel loop can run: two matrices and six tone-curve LUTs,...
int width
Definition format.h:50
int height
Definition format.h:50
#define MAX(a, b)
Definition thinplate.c:29
int dt_tiling_piece_fits_host_memory(const size_t width, const size_t height, const unsigned bpp, const float factor, const size_t overhead)
Definition tiling.c:1465