Ansel 0.0
A darktable fork - bloat + design vision
Loading...
Searching...
No Matches
tiling.c
Go to the documentation of this file.
1/*
2 This file is part of darktable,
3 Copyright (C) 2011-2014, 2016-2017 Ulrich Pegelow.
4 Copyright (C) 2012 Richard Wonka.
5 Copyright (C) 2012-2014, 2016, 2018 Tobias Ellinghaus.
6 Copyright (C) 2013-2014, 2016 Roman Lebedev.
7 Copyright (C) 2013 Simon Spannagel.
8 Copyright (C) 2014 Bruce Guenter.
9 Copyright (C) 2016 Pedro Côrte-Real.
10 Copyright (C) 2018 Edgardo Hoszowski.
11 Copyright (C) 2019 Andreas Schneider.
12 Copyright (C) 2020-2021 Hubert Kowalski.
13 Copyright (C) 2020-2021 Pascal Obry.
14 Copyright (C) 2020-2021 Ralf Brown.
15 Copyright (C) 2021, 2023, 2025-2026 Aurélien PIERRE.
16 Copyright (C) 2021-2022 Hanno Schwalm.
17 Copyright (C) 2022 Martin Bařinka.
18 Copyright (C) 2024 Alynx Zhou.
19
20 darktable is free software: you can redistribute it and/or modify
21 it under the terms of the GNU General Public License as published by
22 the Free Software Foundation, either version 3 of the License, or
23 (at your option) any later version.
24
25 darktable is distributed in the hope that it will be useful,
26 but WITHOUT ANY WARRANTY; without even the implied warranty of
27 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 GNU General Public License for more details.
29
30 You should have received a copy of the GNU General Public License
31 along with darktable. If not, see <http://www.gnu.org/licenses/>.
32*/
33
34
38#include "develop/tiling.h"
39#include "common/opencl.h"
40#include "develop/pixelpipe.h"
42
43#include <assert.h>
44#include <math.h>
45#include <stdlib.h>
46#include <string.h>
47
48#define CLAMPI(a, mn, mx) ((a) < (mn) ? (mn) : ((a) > (mx) ? (mx) : (a)))
49
50
51/* this defines an additional alignment requirement for opencl image width.
52 It can have strong effects on processing speed. Reasonable values are a
53 power of 2. set to 1 for no effect. */
54#define CL_ALIGNMENT ((piece->dsc_in.filters != 9u) ? 4 : 1)
55
56/* parameter RESERVE for extended roi_in sizes due to inaccuracies when doing
57 roi_out -> roi_in estimations.
58 Needs to be increased if tiling fails due to insufficient buffer sizes. */
59#define RESERVE 5
60
61/* greatest common divisor */
62static unsigned _gcd(unsigned a, unsigned b)
63{
64 unsigned t;
65 while(b != 0)
66 {
67 t = b;
68 b = a % b;
69 a = t;
70 }
71 return MAX(a, 1);
72}
73
74/* least common multiple */
75static unsigned _lcm(unsigned a, unsigned b)
76{
77 return (((unsigned long)a * b) / _gcd(a, b));
78}
79
80
81static inline int _min(int a, int b)
82{
83 return a < b ? a : b;
84}
85
86static inline int _max(int a, int b)
87{
88 return a > b ? a : b;
89}
90
91
92static inline int _align_up(int n, int a)
93{
94 return n + a - (n % a);
95}
96static inline int _align_down(int n, int a)
97{
98 return n - (n % a);
99}
100static inline int _align_close(int n, int a)
101{
102 const int off = n % a;
103 const int shift = (off > a/2) ? a - off : -off;
104 return n + shift;
105}
106
107/*
108 Completely arbitrary... Make that a pref ?
109*/
110static inline int _maximum_number_tiles()
111{
112 return 10000;
113}
114
115static inline void _print_roi(const dt_iop_roi_t *roi, const char *label)
116{
118 fprintf(stderr," {%5d %5d ->%5d %5d (%5dx%5d) %.6f } %s\n",
119 roi->x, roi->y, roi->x + roi->width, roi->y + roi->height, roi->width, roi->height, roi->scale, label);
120}
121
122
123#if 0
124static void
125_nm_constraints(double x[], int n)
126{
127 x[0] = fabs(x[0]);
128 x[1] = fabs(x[1]);
129 x[2] = fabs(x[2]);
130 x[3] = fabs(x[3]);
131
132 if(x[0] > 1.0) x[0] = 1.0 - x[0];
133 if(x[1] > 1.0) x[1] = 1.0 - x[1];
134 if(x[2] > 1.0) x[2] = 1.0 - x[2];
135 if(x[3] > 1.0) x[3] = 1.0 - x[3];
136
137}
138#endif
139
140static double _nm_fitness(double x[], void *params)
141{
142 void **rest = (void **)params;
143 struct dt_iop_module_t *self = (struct dt_iop_module_t *)rest[0];
144 const struct dt_dev_pixelpipe_iop_t *piece = (const struct dt_dev_pixelpipe_iop_t *)rest[1];
145 struct dt_iop_roi_t *iroi = (struct dt_iop_roi_t *)rest[2];
146 struct dt_iop_roi_t *oroi = (struct dt_iop_roi_t *)rest[3];
147 const struct dt_dev_pixelpipe_t *pipe = (const struct dt_dev_pixelpipe_t *)rest[4];
148
149 dt_iop_roi_t oroi_test = *oroi;
150 oroi_test.x = x[0] * piece->iwidth;
151 oroi_test.y = x[1] * piece->iheight;
152 oroi_test.width = x[2] * piece->iwidth;
153 oroi_test.height = x[3] * piece->iheight;
154
155 dt_iop_roi_t iroi_probe = *iroi;
156 dt_dev_pixelpipe_iop_t piece_copy = *piece;
157 self->modify_roi_in(self, pipe, &piece_copy, &oroi_test, &iroi_probe);
158
159 double fitness = 0.0;
160
161 fitness += (double)(iroi_probe.x - iroi->x) * (iroi_probe.x - iroi->x);
162 fitness += (double)(iroi_probe.y - iroi->y) * (iroi_probe.y - iroi->y);
163 fitness += (double)(iroi_probe.width - iroi->width) * (iroi_probe.width - iroi->width);
164 fitness += (double)(iroi_probe.height - iroi->height) * (iroi_probe.height - iroi->height);
165
166 return fitness;
167}
168
169
170static int _nm_fit_output_to_input_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
171 const struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *iroi,
172 dt_iop_roi_t *oroi, int delta)
173{
174 void *rest[5] = { (void *)self, (void *)piece, (void *)iroi, (void *)oroi, (void *)pipe };
175 double start[4] = { (float)oroi->x / piece->iwidth, (float)oroi->y / piece->iheight,
176 (float)oroi->width / piece->iwidth, (float)oroi->height / piece->iheight };
177 double epsilon = (double)delta / MIN(piece->iwidth, piece->iheight);
178 int maxiter = 1000;
179
180 int iter = simplex(_nm_fitness, start, 4, epsilon, 1.0, maxiter, NULL, rest);
181
182 dt_vprint(DT_DEBUG_TILING, "[_nm_fit_output_to_input_roi] simplex: %d, delta: %d, epsilon: %f\n", iter, delta, epsilon);
183
184 oroi->x = start[0] * piece->iwidth;
185 oroi->y = start[1] * piece->iheight;
186 oroi->width = start[2] * piece->iwidth;
187 oroi->height = start[3] * piece->iheight;
188
189 return (iter <= maxiter);
190}
191
192
193
194/* find a matching oroi_full by probing start value of oroi and get corresponding input roi into iroi_probe.
195 We search in two steps. first by a simplicistic iterative search which will succeed in most cases.
196 If this does not converge, we do a downhill simplex (nelder-mead) fitting */
197static int _fit_output_to_input_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
198 const struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *iroi,
199 dt_iop_roi_t *oroi, int delta, int iter)
200{
201 dt_iop_roi_t iroi_probe = *iroi;
202 dt_iop_roi_t save_oroi = *oroi;
203 dt_dev_pixelpipe_iop_t piece_copy = *piece;
204
205 // try to go the easy way. this works in many cases where output is
206 // just like input, only scaled down
207 self->modify_roi_in(self, pipe, &piece_copy, oroi, &iroi_probe);
208 while((abs((int)iroi_probe.x - (int)iroi->x) > delta || abs((int)iroi_probe.y - (int)iroi->y) > delta
209 || abs((int)iroi_probe.width - (int)iroi->width) > delta
210 || abs((int)iroi_probe.height - (int)iroi->height) > delta) && iter > 0)
211 {
212 _print_roi(&iroi_probe, "tile iroi_probe");
213 _print_roi(oroi, "tile oroi old");
214
215 oroi->x += (iroi->x - iroi_probe.x) * oroi->scale / iroi->scale;
216 oroi->y += (iroi->y - iroi_probe.y) * oroi->scale / iroi->scale;
217 oroi->width += (iroi->width - iroi_probe.width) * oroi->scale / iroi->scale;
218 oroi->height += (iroi->height - iroi_probe.height) * oroi->scale / iroi->scale;
219
220 _print_roi(oroi, "tile oroi new");
221
222 piece_copy = *piece;
223 self->modify_roi_in(self, pipe, &piece_copy, oroi, &iroi_probe);
224 iter--;
225 }
226
227 if(iter > 0) return TRUE;
228
229 *oroi = save_oroi;
230
231 // simplicistic approach did not converge.
232 // try simplex downhill fitting now.
233 // it's crucial that we have a good starting point in oroi, else this
234 // will not converge as well.
235 int fit = _nm_fit_output_to_input_roi(self, pipe, piece, iroi, oroi, delta);
236 return fit;
237}
238
239
240/* simple tiling algorithm for roi_in == roi_out, i.e. for pixel to pixel modules/operations */
241static int _default_process_tiling_ptp(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
242 const struct dt_dev_pixelpipe_iop_t *piece,
243 const void *const ivoid, void *const ovoid,
244 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
245 const int in_bpp)
246{
247 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
248 void *input = NULL;
249 void *output = NULL;
250 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] **** tiling module '%s' for image with size %dx%d --> %dx%d\n",
251 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
252 const int out_bpp = piece->dsc_out.bpp;
253
254 const int ipitch = roi_in->width * in_bpp;
255 const int opitch = roi_out->width * out_bpp;
256 const int max_bpp = _max(in_bpp, out_bpp);
257
258 /* get tiling requirements of module */
260 self->tiling_callback(self, pipe, piece, &tiling);
261
262 /* tiling really does not make sense in these cases. standard process() is not better or worse than we are
263 */
264 if((tiling.factor < 2.2f)
265 && (tiling.overhead < 0.2f * roi_in->width * roi_in->height * max_bpp))
266 {
267 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] no need to use tiling for module '%s' as no real "
268 "memory saving to be expected\n", self->op);
269 goto fallback;
270 }
271
272 /* calculate optimal size of tiles */
273 float available = dt_get_available_mem();
274 // Less than 500 MB of planning room is a legitimate runtime state now that
275 // dt_get_available_mem() is capped by live system availability (issue #1083):
276 // tiles just get small. Not an invariant, so no assert.
277 if(available < 500.0f * 1024.0f * 1024.0f)
279 "[tiling] low memory (%.0f MiB): tiling '%s' aggressively\n",
280 available / (1024.0f * 1024.0f), self->op);
281 /* correct for size of ivoid and ovoid which are needed on top of tiling */
282 available = fmaxf(available - ((float)roi_out->width * roi_out->height * out_bpp)
283 - ((float)roi_in->width * roi_in->height * in_bpp) - tiling.overhead,
284 0);
285 /* The working set of a tiled module lives in the pixelpipe cache ARENA,
286 * which serves every allocation from one CONTIGUOUS free run; entries
287 * pinned by the pipe recursion partition its address space, so the byte
288 * headroom above routinely overstates what allocations can actually get.
289 * Cap the plan by the largest free run (with a margin for runs eroding
290 * between planning and execution): the tile working set packs into that
291 * run, so a plan that exceeds it is guaranteed to fail at runtime no
292 * matter how much total memory is nominally free. */
293 const float largest_run
295 available = fminf(available, 0.9f * largest_run);
296
297 /* Size the tile from the memory left in the host cache.
298 Using the generic singlebuffer floor here can oversize tiles for modules whose
299 scratch buffers scale with tiling.factor, which defeats tiling and makes the
300 tile-local allocations fail later on. */
301 const float factor = fmaxf(tiling.factor, 1.0f);
302 const float maxbuf = fmaxf(tiling.maxbuf, 1.0f);
303 const float singlebuffer = available / factor;
304
305 int width = roi_in->width;
306 int height = roi_in->height;
307
308 /* shrink tile size in case it would exceed singlebuffer size */
309 if((float)width * height * max_bpp * maxbuf > singlebuffer)
310 {
311 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
312
313 /* TODO: can we make this more efficient to minimize total overlap between tiles? */
314 if(width < height && scale >= 0.333f)
315 {
316 height = floorf(height * scale);
317 }
318 else if(height <= width && scale >= 0.333f)
319 {
320 width = floorf(width * scale);
321 }
322 else
323 {
324 width = floorf(width * sqrtf(scale));
325 height = floorf(height * sqrtf(scale));
326 }
327 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_ptp] buffer exceeds singlebuffer, corrected to %dx%d\n",
328 width, height);
329 }
330
331 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
332 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
333 {
334 width = height = floorf(sqrtf((float)width * height));
335 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_roi] use squares because of overlap, corrected to %dx%d\n",
336 width, height);
337 }
338
339 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
340 Modules will report alignment requirements via xalign and yalign within tiling_callback().
341 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
342 direction.
343 We guarantee alignment by selecting image width/height and overlap accordingly. For a tile width/height
344 that is identical to image width/height no special alignment is needed. */
345
346 const unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
347
348 assert(xyalign != 0);
349
350 /* properly align tile width and height by making them smaller if needed */
351 if(width < roi_in->width) width = (width / xyalign) * xyalign;
352 if(height < roi_in->height) height = (height / xyalign) * xyalign;
353
354 /* also make sure that overlap follows alignment rules by making it wider when needed */
355 const int overlap = tiling.overlap % xyalign != 0 ? (tiling.overlap / xyalign + 1) * xyalign
356 : tiling.overlap;
357
358 /* calculate effective tile size */
359 const int tile_wd = width - 2 * overlap > 0 ? width - 2 * overlap : 1;
360 const int tile_ht = height - 2 * overlap > 0 ? height - 2 * overlap : 1;
361
362 /* calculate number of tiles */
363 const int tiles_x = width < roi_in->width ? ceilf(roi_in->width / (float)tile_wd) : 1;
364 const int tiles_y = height < roi_in->height ? ceilf(roi_in->height / (float)tile_ht) : 1;
365
366 /* sanity check: don't run wild on too many tiles */
367 if(tiles_x * tiles_y > _maximum_number_tiles())
368 {
369 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] gave up tiling for module '%s'. too many tiles: %d x %d\n",
370 self->op, tiles_x, tiles_y);
371 goto error;
372 }
373
374 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] (%dx%d) tiles with max dimensions %dx%d and overlap %d\n",
375 tiles_x, tiles_y, width, height, overlap);
376
377 /* reserve input and output buffers for tiles */
379 (size_t)width * height * in_bpp,
380 pipe->type);
381 if(IS_NULL_PTR(input))
382 {
383 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] could not alloc input buffer for module '%s'\n",
384 self->op);
385 goto error;
386 }
388 (size_t)width * height * out_bpp,
389 pipe->type);
390 if(IS_NULL_PTR(output))
391 {
392 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] could not alloc output buffer for module '%s'\n",
393 self->op);
394 goto error;
395 }
396
397 /* iterate over tiles */
398 for(size_t tx = 0; tx < tiles_x; tx++)
399 {
400 const size_t wd = tx * tile_wd + width > roi_in->width ? roi_in->width - tx * tile_wd : width;
401 for(size_t ty = 0; ty < tiles_y; ty++)
402 {
403 mutable_pipe->tiling = 1;
404
405 const size_t ht = ty * tile_ht + height > roi_in->height ? roi_in->height - ty * tile_ht : height;
406
407 /* no need to process end-tiles that are smaller than the total overlap area */
408 if((wd <= 2 * overlap && tx > 0) || (ht <= 2 * overlap && ty > 0)) continue;
409
410 /* origin and region of effective part of tile, which we want to store later */
411 size_t origin[] = { 0, 0, 0 };
412 size_t region[] = { wd, ht, 1 };
413
414 /* roi_in and roi_out for process_cl on subbuffer */
415 dt_iop_roi_t iroi = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
416 dt_iop_roi_t oroi = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
417
418 /* offsets of tile into ivoid and ovoid */
419 const size_t ioffs = (ty * tile_ht) * ipitch + (tx * tile_wd) * in_bpp;
420 size_t ooffs = (ty * tile_ht) * opitch + (tx * tile_wd) * out_bpp;
421
422 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] tile (%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT ") with %" G_GSIZE_FORMAT "x%" G_GSIZE_FORMAT " at origin [%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT "]\n",
423 tx, ty, wd, ht, tx * tile_wd, ty * tile_ht);
424
425/* prepare input tile buffer */
427 for(size_t j = 0; j < ht; j++)
428 memcpy((char *)input + j * wd * in_bpp, (char *)ivoid + ioffs + j * ipitch, (size_t)wd * in_bpp);
429
430 /* call process() of module */
431 dt_dev_pixelpipe_iop_t piece_tile = *piece;
432 piece_tile.roi_in = iroi;
433 piece_tile.roi_out = oroi;
434 int err = self->process(self, pipe, &piece_tile, input, output);
435 if(err)
436 {
439 mutable_pipe->tiling = 0;
440 return err;
441 }
442
443 /* correct origin and region of tile for overlap.
444 make sure that we only copy back the "good" part. */
445 if(tx > 0)
446 {
447 origin[0] += overlap;
448 region[0] -= overlap;
449 ooffs += (size_t)overlap * out_bpp;
450 }
451 if(ty > 0)
452 {
453 origin[1] += overlap;
454 region[1] -= overlap;
455 ooffs += (size_t)overlap * opitch;
456 }
457
458/* copy "good" part of tile to output buffer */
460 for(size_t j = 0; j < region[1]; j++)
461 memcpy((char *)ovoid + ooffs + j * opitch,
462 (char *)output + ((j + origin[1]) * wd + origin[0]) * out_bpp, (size_t)region[0] * out_bpp);
463 }
464 }
465
468 mutable_pipe->tiling = 0;
469 return 0;
470
471error:
472 dt_pipeline_message(_("tiling failed for module '%s'. output might be garbled."), self->op);
473// fall through
474
475fallback:
478 mutable_pipe->tiling = 0;
479 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] fall back to standard processing for module '%s'\n",
480 self->op);
481 int err = self->process(self, pipe, piece, ivoid, ovoid);
482 return err;
483}
484
485
486
487/* more elaborate tiling algorithm for roi_in != roi_out: slower than the ptp variant,
488 more tiles and larger overlap */
489static int _default_process_tiling_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
490 const struct dt_dev_pixelpipe_iop_t *piece,
491 const void *const ivoid, void *const ovoid,
492 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
493 const int in_bpp)
494{
495 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
496 void *input = NULL;
497 void *output = NULL;
498
499 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] **** tiling module '%s' for image input size %dx%d --> %dx%d\n",
500 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
501 _print_roi(roi_in, "module roi_in");
502 _print_roi(roi_out, "module roi_out");
503
504 const int out_bpp = piece->dsc_out.bpp;
505
506 const int ipitch = roi_in->width * in_bpp;
507 const int opitch = roi_out->width * out_bpp;
508 const int max_bpp = _max(in_bpp, out_bpp);
509
510 float fullscale = fmaxf(roi_in->scale / roi_out->scale, sqrtf(((float)roi_in->width * roi_in->height)
511 / ((float)roi_out->width * roi_out->height)));
512
513 /* inaccuracy for roi_in elements in roi_out -> roi_in calculations */
514 const int delta = ceilf(fullscale);
515
516 /* estimate for additional (space) requirement in buffer dimensions due to inaccuracies */
517 const int inacc = RESERVE * delta;
518
519 /* get tiling requirements of module */
521 self->tiling_callback(self, pipe, piece, &tiling);
522
523 /* tiling really does not make sense in these cases. standard process() is not better or worse than we are
524 */
525 if((tiling.factor < 2.2f && tiling.overhead < 0.2f * roi_in->width * roi_in->height * max_bpp))
526 {
527 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] no need to use tiling for module '%s' as no memory saving is expected\n",
528 self->op);
529 goto fallback;
530 }
531
532 /* calculate optimal size of tiles */
533 float available = dt_get_available_mem();
534 // Less than 500 MB of planning room is a legitimate runtime state now that
535 // dt_get_available_mem() is capped by live system availability (issue #1083):
536 // tiles just get small. Not an invariant, so no assert.
537 if(available < 500.0f * 1024.0f * 1024.0f)
539 "[tiling] low memory (%.0f MiB): tiling '%s' aggressively\n",
540 available / (1024.0f * 1024.0f), self->op);
541 /* correct for size of ivoid and ovoid which are needed on top of tiling */
542 available = fmaxf(available - ((float)roi_out->width * roi_out->height * out_bpp)
543 - ((float)roi_in->width * roi_in->height * in_bpp) - tiling.overhead,
544 0);
545 /* The working set of a tiled module lives in the pixelpipe cache ARENA,
546 * which serves every allocation from one CONTIGUOUS free run; entries
547 * pinned by the pipe recursion partition its address space, so the byte
548 * headroom above routinely overstates what allocations can actually get.
549 * Cap the plan by the largest free run (with a margin for runs eroding
550 * between planning and execution): the tile working set packs into that
551 * run, so a plan that exceeds it is guaranteed to fail at runtime no
552 * matter how much total memory is nominally free. */
553 const float largest_run
555 available = fminf(available, 0.9f * largest_run);
556
557 /* Size the tile from the memory left in the host cache.
558 Using the generic singlebuffer floor here can oversize tiles for modules whose
559 scratch buffers scale with tiling.factor, which defeats tiling and makes the
560 tile-local allocations fail later on. */
561 const float factor = fmaxf(tiling.factor, 1.0f);
562 const float maxbuf = fmaxf(tiling.maxbuf, 1.0f);
563 const float singlebuffer = available / factor;
564
565 int width = _max(roi_in->width, roi_out->width);
566 int height = _max(roi_in->height, roi_out->height);
567
568 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
569 Modules will report alignment requirements via xalign and yalign within tiling_callback().
570 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
571 direction. */
572
573 /* for simplicity reasons we use only one alignment that fits to x and y requirements at the same time */
574 const unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
575
576 assert(xyalign != 0);
577
578 /* shrink tile size in case it would exceed singlebuffer size */
579 if((float)width * height * max_bpp * maxbuf > singlebuffer)
580 {
581 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
582
583 /* TODO: can we make this more efficient to minimize total overlap between tiles? */
584 if(width < height && scale >= 0.333f)
585 {
586 height = _align_down((int)floorf(height * scale), xyalign);
587 }
588 else if(height <= width && scale >= 0.333f)
589 {
590 width = _align_down((int)floorf(width * scale), xyalign);
591 }
592 else
593 {
594 width = _align_down((int)floorf(width * sqrtf(scale)), xyalign);
595 height = _align_down((int)floorf(height * sqrtf(scale)), xyalign);
596 }
597 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_roi] buffer exceeds singlebuffer, corrected to %dx%d\n",
598 width, height);
599 }
600
601 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
602 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
603 {
604 width = height = _align_down((int)floorf(sqrtf((float)width * height)), xyalign);
605 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_roi] use squares because of overlap, corrected to %dx%d\n",
606 width, height);
607 }
608
609 /* make sure that overlap follows alignment rules by making it wider when needed.
610 overlap_in needs to be aligned, overlap_out is only here to calculate output buffer size */
611 const int overlap_in = _align_up(tiling.overlap, xyalign);
612 const int overlap_out = ceilf((float)overlap_in / fullscale);
613
614 int tiles_x = 1, tiles_y = 1;
615
616 /* calculate number of tiles taking the larger buffer (input or output) as a guiding one.
617 normally it is roi_in > roi_out; but let's be prepared */
618 if(roi_in->width > roi_out->width)
619 tiles_x = width < roi_in->width
620 ? ceilf((float)roi_in->width / (float)_max(width - 2 * overlap_in - inacc, 1))
621 : 1;
622 else
623 tiles_x = width < roi_out->width ? ceilf((float)roi_out->width / (float)_max(width - 2 * overlap_out, 1))
624 : 1;
625
626 if(roi_in->height > roi_out->height)
627 tiles_y = height < roi_in->height
628 ? ceilf((float)roi_in->height / (float)_max(height - 2 * overlap_in - inacc, 1))
629 : 1;
630 else
631 tiles_y = height < roi_out->height
632 ? ceilf((float)roi_out->height / (float)_max(height - 2 * overlap_out, 1))
633 : 1;
634
635 /* sanity check: don't run wild on too many tiles */
636 if(tiles_x * tiles_y > _maximum_number_tiles())
637 {
638 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] gave up tiling for module '%s'. too many tiles: %d x %d\n",
639 self->op, tiles_x, tiles_y);
640 goto error;
641 }
642
643
644 /* calculate tile width and height excl. overlap (i.e. the good part) for output.
645 values are important for all following processing steps. */
646 const int tile_wd = _align_up(
647 roi_out->width % tiles_x == 0 ? roi_out->width / tiles_x : roi_out->width / tiles_x + 1, xyalign);
648 const int tile_ht = _align_up(
649 roi_out->height % tiles_y == 0 ? roi_out->height / tiles_y : roi_out->height / tiles_y + 1, xyalign);
650
651 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] (%dx%d) tiles with max dimensions %dx%d, good %dx%d, overlap %d->%d\n",
652 tiles_x, tiles_y, width, height, tile_wd, tile_ht, overlap_in, overlap_out);
653
654 /* iterate over tiles */
655 for(size_t tx = 0; tx < tiles_x; tx++)
656 for(size_t ty = 0; ty < tiles_y; ty++)
657 {
658 mutable_pipe->tiling = 1;
659
660 /* the output dimensions of the good part of this specific tile */
661 const size_t wd = (tx + 1) * tile_wd > roi_out->width ? (size_t)roi_out->width - tx * tile_wd : tile_wd;
662 const size_t ht = (ty + 1) * tile_ht > roi_out->height ? (size_t)roi_out->height - ty * tile_ht : tile_ht;
663
664 /* roi_in and roi_out of good part: oroi_good easy to calculate based on number and dimension of tile.
665 iroi_good is calculated by modify_roi_in() of respective module */
666 dt_iop_roi_t iroi_good = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
667 dt_iop_roi_t oroi_good = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
668
669 dt_dev_pixelpipe_iop_t piece_copy = *piece;
670 self->modify_roi_in(self, pipe, &piece_copy, &oroi_good, &iroi_good);
671
672 /* clamp iroi_good to not exceed roi_in */
673 iroi_good.x = _max(iroi_good.x, roi_in->x);
674 iroi_good.y = _max(iroi_good.y, roi_in->y);
675 iroi_good.width = _min(iroi_good.width, roi_in->width + roi_in->x - iroi_good.x);
676 iroi_good.height = _min(iroi_good.height, roi_in->height + roi_in->y - iroi_good.y);
677
678 _print_roi(&iroi_good, "tile iroi_good");
679 _print_roi(&oroi_good, "tile oroi_good");
680
681 /* now we need to calculate full region of this tile: increase input roi to take care of overlap
682 requirements
683 and alignment and add additional delta to correct for possible rounding errors in modify_roi_in()
684 -> generates first estimate of iroi_full */
685 const int x_in = iroi_good.x;
686 const int y_in = iroi_good.y;
687 const int width_in = iroi_good.width;
688 const int height_in = iroi_good.height;
689 const int new_x_in = _max(_align_close(x_in - overlap_in - delta, xyalign), roi_in->x);
690 const int new_y_in = _max(_align_close(y_in - overlap_in - delta, xyalign), roi_in->y);
691 const int new_width_in = _min(_align_up(width_in + overlap_in + delta + (x_in - new_x_in), xyalign),
692 roi_in->width + roi_in->x - new_x_in);
693 const int new_height_in = _min(_align_up(height_in + overlap_in + delta + (y_in - new_y_in), xyalign),
694 roi_in->height + roi_in->y - new_y_in);
695
696 /* iroi_full based on calculated numbers and dimensions. oroi_full just set as a starting point for the
697 * following iterative search */
698 dt_iop_roi_t iroi_full = { new_x_in, new_y_in, new_width_in, new_height_in, iroi_good.scale };
699 dt_iop_roi_t oroi_full = oroi_good; // a good starting point for optimization
700
701 _print_roi(&iroi_full, "tile iroi_full before optimization");
702 _print_roi(&oroi_full, "tile oroi_full before optimization");
703
704 /* try to find a matching oroi_full */
705 if(!_fit_output_to_input_roi(self, pipe, piece, &iroi_full, &oroi_full, delta, 10))
706 {
707 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] can not handle requested roi's. tiling for "
708 "module '%s' not possible.\n",
709 self->op);
710 goto error;
711 }
712
713 _print_roi(&iroi_full, "tile iroi_full after optimization");
714 _print_roi(&oroi_full, "tile oroi_full after optimization");
715
716 /* make sure that oroi_full at least covers the range of oroi_good.
717 this step is needed due to the possibility of rounding errors */
718 oroi_full.x = _min(oroi_full.x, oroi_good.x);
719 oroi_full.y = _min(oroi_full.y, oroi_good.y);
720 oroi_full.width = _max(oroi_full.width, oroi_good.x + oroi_good.width - oroi_full.x);
721 oroi_full.height = _max(oroi_full.height, oroi_good.y + oroi_good.height - oroi_full.y);
722
723 /* clamp oroi_full to not exceed roi_out */
724 oroi_full.x = _max(oroi_full.x, roi_out->x);
725 oroi_full.y = _max(oroi_full.y, roi_out->y);
726 oroi_full.width = _min(oroi_full.width, roi_out->width + roi_out->x - oroi_full.x);
727 oroi_full.height = _min(oroi_full.height, roi_out->height + roi_out->y - oroi_full.y);
728
729 /* calculate final iroi_full */
730 dt_dev_pixelpipe_iop_t piece_full = *piece;
731 self->modify_roi_in(self, pipe, &piece_full, &oroi_full, &iroi_full);
732
733 /* clamp iroi_full to not exceed roi_in */
734 iroi_full.x = _max(iroi_full.x, roi_in->x);
735 iroi_full.y = _max(iroi_full.y, roi_in->y);
736 iroi_full.width = _min(iroi_full.width, roi_in->width + roi_in->x - iroi_full.x);
737 iroi_full.height = _min(iroi_full.height, roi_in->height + roi_in->y - iroi_full.y);
738
739 _print_roi(&iroi_full, "tile iroi_full final");
740 _print_roi(&oroi_full, "tile oroi_full final");
741
742 /* offsets of tile into ivoid and ovoid */
743 const size_t ioffs = ((size_t)iroi_full.y - roi_in->y) * ipitch + ((size_t)iroi_full.x - roi_in->x) * in_bpp;
744 size_t ooffs = ((size_t)oroi_good.y - roi_out->y) * opitch + ((size_t)oroi_good.x - roi_out->x) * out_bpp;
745
746 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] process tile (%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT ") size %dx%d at origin [%d,%d]\n",
747 tx, ty, iroi_full.width, iroi_full.height, iroi_full.x, iroi_full.y);
748
749 /* prepare input tile buffer */
751 (size_t)iroi_full.width * iroi_full.height * in_bpp,
752 pipe->type);
753 if(IS_NULL_PTR(input))
754 {
755 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] could not alloc input buffer for module '%s'\n",
756 self->op);
757 goto error;
758 }
760 (size_t)oroi_full.width * oroi_full.height * out_bpp,
761 pipe->type);
762 if(IS_NULL_PTR(output))
763 {
764 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] could not alloc output buffer for module '%s'\n",
765 self->op);
766 goto error;
767 }
769 for(size_t j = 0; j < iroi_full.height; j++)
770 memcpy((char *)input + j * iroi_full.width * in_bpp, (char *)ivoid + ioffs + j * ipitch,
771 (size_t)iroi_full.width * in_bpp);
772
773 /* call process() of module */
774 dt_dev_pixelpipe_iop_t piece_tile = *piece;
775 piece_tile.roi_in = iroi_full;
776 piece_tile.roi_out = oroi_full;
777 int err = self->process(self, pipe, &piece_tile, input, output);
778 if(err)
779 {
782 mutable_pipe->tiling = 0;
783 return err;
784 }
785
786 /* copy "good" part of tile to output buffer */
787 const int origin_x = oroi_good.x - oroi_full.x;
788 const int origin_y = oroi_good.y - oroi_full.y;
790 for(size_t j = 0; j < oroi_good.height; j++)
791 memcpy((char *)ovoid + ooffs + j * opitch,
792 (char *)output + ((j + origin_y) * oroi_full.width + origin_x) * out_bpp,
793 (size_t)oroi_good.width * out_bpp);
794
797 input = output = NULL;
798 }
799
802 mutable_pipe->tiling = 0;
803 return 0;
804
805error:
806 dt_pipeline_message(_("tiling failed for module '%s'. output might be garbled."), self->op);
807// fall through
808
809fallback:
812 mutable_pipe->tiling = 0;
813 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] fall back to standard processing for module '%s'\n",
814 self->op);
815 int err = self->process(self, pipe, piece, ivoid, ovoid);
816 return err;
817}
818
819
820
821/* if a module does not implement process_tiling() by itself, this function is called instead.
822 _default_process_tiling_ptp() is able to handle standard cases where pixels do not change their places.
823 _default_process_tiling_roi() takes care of all other cases where image gets distorted and for module
824 "clipping",
825 "flip" as this may flip or mirror the image. */
826int default_process_tiling(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
827 const struct dt_dev_pixelpipe_iop_t *piece,
828 const void *const ivoid, void *const ovoid, const int in_bpp)
829{
830 const dt_iop_roi_t *const roi_in = &piece->roi_in;
831 const dt_iop_roi_t *const roi_out = &piece->roi_out;
832 if(memcmp(roi_in, roi_out, sizeof(struct dt_iop_roi_t)) || (self->flags() & IOP_FLAGS_TILING_FULL_ROI))
833 return _default_process_tiling_roi(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
834 else
835 return _default_process_tiling_ptp(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
836}
837
838
839
840#ifdef HAVE_OPENCL
841/* simple tiling algorithm for roi_in == roi_out, i.e. for pixel to pixel modules/operations */
842static int _default_process_tiling_cl_ptp(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
843 const struct dt_dev_pixelpipe_iop_t *piece,
844 const void *const ivoid, void *const ovoid,
845 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
846 const int in_bpp)
847{
848 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
849 cl_int err = -999;
850 cl_mem input = NULL;
851 cl_mem output = NULL;
852
853 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] **** tiling module '%s' for image with size %dx%d --> %dx%d\n",
854 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
855
856 const int out_bpp = piece->dsc_out.bpp;
857
858 const int devid = pipe->devid;
859 const int ipitch = roi_in->width * in_bpp;
860 const int opitch = roi_out->width * out_bpp;
861 const int max_bpp = _max(in_bpp, out_bpp);
862
863 /* get tiling requirements of module */
865 self->tiling_callback(self, pipe, piece, &tiling);
866
867 // avoid problems when pinned buffer size gets too close to max_mem_alloc size
868 const float available = (float)dt_opencl_get_device_available(devid);
869 const float factor = fmaxf(tiling.factor_cl, 1.0f);
870 const float singlebuffer = fminf(fmaxf((available - tiling.overhead) / factor, 0.0f),
872 const float maxbuf = fmaxf(tiling.maxbuf_cl, 1.0f);
873 int max_width = 0, max_height = 0;
874 dt_opencl_get_device_max_image_size(devid, &max_width, &max_height);
875 int width = _min(roi_in->width, max_width);
876 int height = _min(roi_in->height, max_height);
877
878 /* shrink tile size in case it would exceed singlebuffer size */
879 if((float)width * height * max_bpp * maxbuf > singlebuffer)
880 {
881 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
882
883 if(width < height && scale >= 0.333f)
884 {
885 height = floorf(height * scale);
886 }
887 else if(height <= width && scale >= 0.333f)
888 {
889 width = floorf(width * scale);
890 }
891 else
892 {
893 width = floorf(width * sqrtf(scale));
894 height = floorf(height * sqrtf(scale));
895 }
896 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] buffer exceeds singlebuffer, corrected to %dx%d\n",
897 width, height);
898 }
899
900 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
901 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
902 {
903 width = height = floorf(sqrtf((float)width * height));
904 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] use squares because of overlap, corrected to %dx%d\n",
905 width, height);
906 }
907
908 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
909 Modules will report alignment requirements via xalign and yalign within tiling_callback().
910 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
911 direction. Additional alignment requirements are set via definition of CL_ALIGNMENT.
912 We guarantee alignment by selecting image width/height and overlap accordingly. For a tile width/height
913 that is identical to image width/height no special alignment is done. */
914
915 /* for simplicity reasons we use only one alignment that fits to x and y requirements at the same time */
916 const unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
917
918 /* determining alignment requirement for tile width/height.
919 in case of tile width also align according to definition of CL_ALIGNMENT */
920 const unsigned int walign = _lcm(xyalign, CL_ALIGNMENT);
921 const unsigned int halign = xyalign;
922
923 assert(xyalign != 0 && walign != 0 && halign != 0);
924
925 /* properly align tile width and height by making them smaller if needed */
926 if(width < roi_in->width) width = (width / walign) * walign;
927 if(height < roi_in->height) height = (height / halign) * halign;
928
929 /* OpenCL image allocations are backed by device-specific row/height strides.
930 The generic full-frame pre-check already reasons on rounded dimensions, so
931 tiling needs to use the same planning rule or it may pick a tile that fits
932 mathematically in width*height*bpp but still fails once the driver rounds it
933 up internally. Shrink the candidate tile until the rounded image footprint
934 fits the per-buffer budget. */
935 while((float)ROUNDUPDWD(width, devid) * ROUNDUPDHT(height, devid) * max_bpp * maxbuf > singlebuffer)
936 {
937 if(width <= (int)walign && height <= (int)halign) break;
938 if(width < height && height > (int)halign)
939 height -= halign;
940 else if(width > (int)walign)
941 width -= walign;
942 else
943 height -= halign;
944 }
945
946 /* The loop above subtracts whole multiples of the alignment, which preserves alignment only
947 if the value it started from was already aligned. That is not guaranteed here: the
948 alignment step further up is deliberately skipped while a dimension still spans the whole
949 image -- correct as long as it stays that way, but this loop is free to shrink such a
950 dimension below the image size, and it then carries the image's own arbitrary size as a
951 permanent phase error. Tile origins step by (dimension - 2 * overlap), so one unaligned
952 dimension puts every tile after the first off-lattice, and with it every lattice a module
953 anchors to its own tile origin -- CFA phase, superpixel binning, pyramid levels. */
954 if(width < roi_in->width) width = _max((int)walign, _align_down(width, walign));
955 if(height < roi_in->height) height = _max((int)halign, _align_down(height, halign));
956
957 /* also make sure that overlap follows alignment rules by making it wider when needed */
958 const int overlap = tiling.overlap % xyalign != 0 ? (tiling.overlap / xyalign + 1) * xyalign
959 : tiling.overlap;
960
961
962 /* calculate effective tile size */
963 const int tile_wd = width - 2 * overlap > 0 ? width - 2 * overlap : 1;
964 const int tile_ht = height - 2 * overlap > 0 ? height - 2 * overlap : 1;
965
966
967 /* calculate number of tiles */
968 const int tiles_x = width < roi_in->width ? ceilf(roi_in->width / (float)tile_wd) : 1;
969 const int tiles_y = height < roi_in->height ? ceilf(roi_in->height / (float)tile_ht) : 1;
970
971 /* sanity check: don't run wild on too many tiles */
972 if(tiles_x * tiles_y > _maximum_number_tiles())
973 {
974 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] aborted tiling for module '%s'. too many tiles: %d x %d\n",
975 self->op, tiles_x, tiles_y);
976 return FALSE;
977 }
978
979 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] (%dx%d) tiles with max dimensions %dx%d, good %dx%d and overlap %d\n",
980 tiles_x, tiles_y, width, height, tile_wd, tile_ht, overlap);
981
982 /* iterate over tiles */
983 for(size_t tx = 0; tx < tiles_x; tx++)
984 for(size_t ty = 0; ty < tiles_y; ty++)
985 {
986 mutable_pipe->tiling = 1;
987
988 const size_t wd = tx * tile_wd + width > roi_in->width ? roi_in->width - tx * tile_wd : width;
989 const size_t ht = ty * tile_ht + height > roi_in->height ? roi_in->height - ty * tile_ht : height;
990
991 /* no need to process (end)tiles that are smaller than the total overlap area */
992 if((wd <= 2 * overlap && tx > 0) || (ht <= 2 * overlap && ty > 0)) continue;
993
994 /* origin and region of effective part of tile, which we want to store later */
995 size_t origin[] = { 0, 0, 0 };
996 size_t region[] = { wd, ht, 1 };
997
998 /* roi_in and roi_out for process_cl on subbuffer */
999 dt_iop_roi_t iroi = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
1000 dt_iop_roi_t oroi = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
1001
1002
1003 /* offsets of tile into ivoid and ovoid */
1004 const size_t ioffs = (ty * tile_ht) * ipitch + (tx * tile_wd) * in_bpp;
1005 size_t ooffs = (ty * tile_ht) * opitch + (tx * tile_wd) * out_bpp;
1006
1007
1008 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] tile (%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT ") size %" G_GSIZE_FORMAT "x%" G_GSIZE_FORMAT " at origin [%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT "]\n",
1009 tx, ty, wd, ht, tx * tile_wd, ty * tile_ht);
1010
1011 /* get input and output buffers */
1012 input = dt_opencl_alloc_device(devid, wd, ht, in_bpp);
1013 if(IS_NULL_PTR(input)) goto error;
1014 output = dt_opencl_alloc_device(devid, wd, ht, out_bpp);
1015 if(IS_NULL_PTR(output)) goto error;
1016
1017 /* blocking direct memory transfer: host input image -> opencl/device tile */
1018 err = dt_opencl_write_host_to_device_raw(devid, (char *)ivoid + ioffs, input, origin, region, ipitch,
1019 CL_TRUE);
1020 if(err != CL_SUCCESS) goto error;
1021
1022 /* call process_cl of module */
1023 dt_dev_pixelpipe_iop_t piece_tile = *piece;
1024 piece_tile.roi_in = iroi;
1025 piece_tile.roi_out = oroi;
1026 if(!self->process_cl(self, pipe, &piece_tile, input, output)) goto error;
1027
1028 /* correct origin and region of tile for overlap.
1029 makes sure that we only copy back the "good" part. */
1030 if(tx > 0)
1031 {
1032 origin[0] += overlap;
1033 region[0] -= overlap;
1034 ooffs += (size_t)overlap * out_bpp;
1035 }
1036 if(ty > 0)
1037 {
1038 origin[1] += overlap;
1039 region[1] -= overlap;
1040 ooffs += (size_t)overlap * opitch;
1041 }
1042
1043 /* blocking direct memory transfer: good part of opencl/device tile -> host output image */
1044 err = dt_opencl_read_host_from_device_raw(devid, (char *)ovoid + ooffs, output, origin, region,
1045 opitch, CL_TRUE);
1046 if(err != CL_SUCCESS) goto error;
1047
1048 /* release input and output buffers */
1050 input = NULL;
1052 output = NULL;
1053
1054 /* block until opencl queue has finished to free all used event handlers */
1056 }
1057
1060 mutable_pipe->tiling = 0;
1061 return TRUE;
1062
1063error:
1066 mutable_pipe->tiling = 0;
1068 "[default_process_tiling_opencl_ptp] couldn't run process_cl() for module '%s' in tiling mode: %i\n",
1069 self->op, err);
1070 return FALSE;
1071}
1072
1073
1074/* more elaborate tiling algorithm for roi_in != roi_out: slower than the ptp variant,
1075 more tiles and larger overlap */
1076static int _default_process_tiling_cl_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1077 const struct dt_dev_pixelpipe_iop_t *piece,
1078 const void *const ivoid, void *const ovoid,
1079 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
1080 const int in_bpp)
1081{
1082 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
1083 cl_int err = -999;
1084 cl_mem input = NULL;
1085 cl_mem output = NULL;
1086
1088 "[default_process_tiling_cl_roi] **** tiling module '%s' for image with input size %dx%d --> %dx%d\n",
1089 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
1090 _print_roi(roi_in, "module roi_in");
1091 _print_roi(roi_out, "module roi_out");
1092
1093 const int out_bpp = piece->dsc_out.bpp;
1094
1095 const int devid = pipe->devid;
1096 const int ipitch = roi_in->width * in_bpp;
1097 const int opitch = roi_out->width * out_bpp;
1098 const int max_bpp = _max(in_bpp, out_bpp);
1099
1100 const float fullscale = fmaxf(roi_in->scale / roi_out->scale, sqrtf(((float)roi_in->width * roi_in->height)
1101 / ((float)roi_out->width * roi_out->height)));
1102
1103 /* inaccuracy for roi_in elements in roi_out -> roi_in calculations */
1104 const int delta = ceilf(fullscale);
1105
1106 /* estimate for additional (space) requirement in buffer dimensions due to inaccuracies */
1107 const int inacc = RESERVE * delta;
1108
1109 /* get tiling requirements of module */
1111 self->tiling_callback(self, pipe, piece, &tiling);
1112
1113 // avoid problems when pinned buffer size gets too close to max_mem_alloc size
1114 const float available = (float)dt_opencl_get_device_available(devid);
1115 const float factor = fmaxf(tiling.factor_cl, 1.0f);
1116 const float singlebuffer = fminf(fmaxf((available - tiling.overhead) / factor, 0.0f),
1118 const float maxbuf = fmaxf(tiling.maxbuf_cl, 1.0f);
1119
1120 int max_width = 0, max_height = 0;
1121 dt_opencl_get_device_max_image_size(devid, &max_width, &max_height);
1122 int width = _min(_max(roi_in->width, roi_out->width), max_width);
1123 int height = _min(_max(roi_in->height, roi_out->height), max_height);
1124
1125 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
1126 Modules will report alignment requirements via xalign and yalign within tiling_callback().
1127 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
1128 direction. Additional alignment requirements are set via definition of CL_ALIGNMENT. */
1129
1130 /* for simplicity reasons we use only one alignment that fits to x and y requirements at the same time */
1131 unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
1132 xyalign = _lcm(xyalign, CL_ALIGNMENT);
1133
1134 assert(xyalign != 0);
1135
1136 /* shrink tile size in case it would exceed singlebuffer size */
1137 if((float)width * height * max_bpp * maxbuf > singlebuffer)
1138 {
1139 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
1140
1141 if(width < height && scale >= 0.333f)
1142 {
1143 height = _align_down((int)floorf(height * scale), xyalign);
1144 }
1145 else if(height <= width && scale >= 0.333f)
1146 {
1147 width = _align_down((int)floorf(width * scale), xyalign);
1148 }
1149 else
1150 {
1151 width = _align_down((int)floorf(width * sqrtf(scale)), xyalign);
1152 height = _align_down((int)floorf(height * sqrtf(scale)), xyalign);
1153 }
1154 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_roi] buffer exceeds singlebuffer, corrected to %dx%d\n",
1155 width, height);
1156 }
1157
1158 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
1159 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
1160 {
1161 width = height = _align_down((int)floorf(sqrtf((float)width * height)), xyalign);
1162 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_roi] use squares because of overlap, corrected to %dx%d\n",
1163 width, height);
1164 }
1165
1166 /* make sure that overlap follows alignment rules by making it wider when needed.
1167 overlap_in needs to be aligned, overlap_out is only here to calculate output buffer size */
1168 const int overlap_in = _align_up(tiling.overlap, xyalign);
1169 const int overlap_out = ceilf((float)overlap_in / fullscale);
1170
1171 /* As in the pixel-perfect tiler above, keep planning conservative with the
1172 same rounded OpenCL dimensions used by the non-tiling GPU fit checks. The
1173 ROI path can otherwise accept a tile whose raw area fits `singlebuffer`
1174 even though the driver-backed image allocation for the tile does not. */
1175 while((float)ROUNDUPDWD(width, devid) * ROUNDUPDHT(height, devid) * max_bpp * maxbuf > singlebuffer)
1176 {
1177 if(width <= (int)xyalign && height <= (int)xyalign) break;
1178 if(width < height && height > (int)xyalign)
1179 height -= xyalign;
1180 else if(width > (int)xyalign)
1181 width -= xyalign;
1182 else
1183 height -= xyalign;
1184 }
1185
1186 /* Same re-alignment as in the pixel-perfect tiler above: this loop only preserves the
1187 alignment it was handed, and the branches that set it are all conditional, so a tile that
1188 took none of them reaches here still carrying the raw image dimensions. */
1189 if(width < _max(roi_in->width, roi_out->width)) width = _max((int)xyalign, _align_down(width, xyalign));
1190 if(height < _max(roi_in->height, roi_out->height)) height = _max((int)xyalign, _align_down(height, xyalign));
1191
1192 int tiles_x = 1, tiles_y = 1;
1193
1194 /* calculate number of tiles taking the larger buffer (input or output) as a guiding one.
1195 normally it is roi_in > roi_out; but let's be prepared */
1196 if(roi_in->width > roi_out->width)
1197 tiles_x = width < roi_in->width
1198 ? ceilf((float)roi_in->width / (float)_max(width - 2 * overlap_in - inacc, 1))
1199 : 1;
1200 else
1201 tiles_x = width < roi_out->width ? ceilf((float)roi_out->width / (float)_max(width - 2 * overlap_out, 1))
1202 : 1;
1203
1204 if(roi_in->height > roi_out->height)
1205 tiles_y = height < roi_in->height
1206 ? ceilf((float)roi_in->height / (float)_max(height - 2 * overlap_in - inacc, 1))
1207 : 1;
1208 else
1209 tiles_y = height < roi_out->height
1210 ? ceilf((float)roi_out->height / (float)_max(height - 2 * overlap_out, 1))
1211 : 1;
1212
1213 /* sanity check: don't run wild on too many tiles */
1214 if(tiles_x * tiles_y > _maximum_number_tiles())
1215 {
1217 "[default_process_tiling_cl_roi] aborted tiling for module '%s'. too many tiles: %dx%d\n",
1218 self->op, tiles_x, tiles_y);
1219 return FALSE;
1220 }
1221
1222 /* calculate tile width and height excl. overlap (i.e. the good part) for output.
1223 important for all following processing steps. */
1224 const int tile_wd = _align_up(
1225 roi_out->width % tiles_x == 0 ? roi_out->width / tiles_x : roi_out->width / tiles_x + 1, xyalign);
1226 const int tile_ht = _align_up(
1227 roi_out->height % tiles_y == 0 ? roi_out->height / tiles_y : roi_out->height / tiles_y + 1, xyalign);
1228
1230 "[default_process_tiling_cl_roi] (%dx%d) tiles with max input dimensions %dx%d, good %ix%i\n",
1231 tiles_x, tiles_y, width, height, tile_wd, tile_ht);
1232
1233 /* iterate over tiles */
1234 for(size_t tx = 0; tx < tiles_x; tx++)
1235 for(size_t ty = 0; ty < tiles_y; ty++)
1236 {
1237 mutable_pipe->tiling = 1;
1238
1239 /* the output dimensions of the good part of this specific tile */
1240 const size_t wd = (tx + 1) * tile_wd > roi_out->width ? (size_t)roi_out->width - tx * tile_wd : tile_wd;
1241 const size_t ht = (ty + 1) * tile_ht > roi_out->height ? (size_t)roi_out->height - ty * tile_ht : tile_ht;
1242
1243 /* roi_in and roi_out of good part: oroi_good easy to calculate based on number and dimension of tile.
1244 iroi_good is calculated by modify_roi_in() of respective module */
1245 dt_iop_roi_t iroi_good = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
1246 dt_iop_roi_t oroi_good = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
1247
1248 dt_dev_pixelpipe_iop_t piece_copy = *piece;
1249 self->modify_roi_in(self, pipe, &piece_copy, &oroi_good, &iroi_good);
1250
1251 /* clamp iroi_good to not exceed roi_in */
1252 iroi_good.x = _max(iroi_good.x, roi_in->x);
1253 iroi_good.y = _max(iroi_good.y, roi_in->y);
1254 iroi_good.width = _min(iroi_good.width, roi_in->width + roi_in->x - iroi_good.x);
1255 iroi_good.height = _min(iroi_good.height, roi_in->height + roi_in->y - iroi_good.y);
1256
1257 _print_roi(&iroi_good, "tile iroi_good");
1258 _print_roi(&oroi_good, "tile oroi_good");
1259
1260 /* now we need to calculate full region of this tile: increase input roi to take care of overlap
1261 requirements
1262 and alignment and add additional delta to correct for possible rounding errors in modify_roi_in()
1263 -> generates first estimate of iroi_full */
1264 const int x_in = iroi_good.x;
1265 const int y_in = iroi_good.y;
1266 const int width_in = iroi_good.width;
1267 const int height_in = iroi_good.height;
1268 const int new_x_in = _max(_align_close(x_in - overlap_in - delta, xyalign), roi_in->x);
1269 const int new_y_in = _max(_align_close(y_in - overlap_in - delta, xyalign), roi_in->y);
1270 const int new_width_in = _min(_align_up(width_in + overlap_in + delta + (x_in - new_x_in), xyalign),
1271 roi_in->width + roi_in->x - new_x_in);
1272 const int new_height_in = _min(_align_up(height_in + overlap_in + delta + (y_in - new_y_in), xyalign),
1273 roi_in->height + roi_in->y - new_y_in);
1274
1275 /* iroi_full based on calculated numbers and dimensions. oroi_full just set as a starting point for the
1276 * following iterative search */
1277 dt_iop_roi_t iroi_full = { new_x_in, new_y_in, new_width_in, new_height_in, iroi_good.scale };
1278 dt_iop_roi_t oroi_full = oroi_good; // a good starting point for optimization
1279
1280 _print_roi(&iroi_full, "tile iroi_full before optimization");
1281 _print_roi(&oroi_full, "tile oroi_full before optimization");
1282
1283 /* try to find a matching oroi_full */
1284 if(!_fit_output_to_input_roi(self, pipe, piece, &iroi_full, &oroi_full, delta, 10))
1285 {
1286 dt_print(DT_DEBUG_OPENCL | DT_DEBUG_TILING, "[default_process_tiling_cl_roi] can not handle requested roi's tiling "
1287 "for module '%s' not possible.\n",
1288 self->op);
1289 goto error;
1290 }
1291
1292
1293 /* make sure that oroi_full at least covers the range of oroi_good.
1294 this step is needed due to the possibility of rounding errors */
1295 oroi_full.x = _min(oroi_full.x, oroi_good.x);
1296 oroi_full.y = _min(oroi_full.y, oroi_good.y);
1297 oroi_full.width = _max(oroi_full.width, oroi_good.x + oroi_good.width - oroi_full.x);
1298 oroi_full.height = _max(oroi_full.height, oroi_good.y + oroi_good.height - oroi_full.y);
1299
1300 /* clamp oroi_full to not exceed roi_out */
1301 oroi_full.x = _max(oroi_full.x, roi_out->x);
1302 oroi_full.y = _max(oroi_full.y, roi_out->y);
1303 oroi_full.width = _min(oroi_full.width, roi_out->width + roi_out->x - oroi_full.x);
1304 oroi_full.height = _min(oroi_full.height, roi_out->height + roi_out->y - oroi_full.y);
1305
1306
1307 /* calculate final iroi_full */
1308 dt_dev_pixelpipe_iop_t piece_full = *piece;
1309 self->modify_roi_in(self, pipe, &piece_full, &oroi_full, &iroi_full);
1310
1311 /* clamp iroi_full to not exceed roi_in */
1312 iroi_full.x = _max(iroi_full.x, roi_in->x);
1313 iroi_full.y = _max(iroi_full.y, roi_in->y);
1314 iroi_full.width = _min(iroi_full.width, roi_in->width + roi_in->x - iroi_full.x);
1315 iroi_full.height = _min(iroi_full.height, roi_in->height + roi_in->y - iroi_full.y);
1316
1317 _print_roi(&iroi_full, "tile iroi_full");
1318 _print_roi(&oroi_full, "tile oroi_full");
1319
1320 /* offsets of tile into ivoid and ovoid */
1321 const int in_dx = iroi_full.x - roi_in->x;
1322 const int in_dy = iroi_full.y - roi_in->y;
1323 const int out_dx = oroi_good.x - roi_out->x;
1324 const int out_dy = oroi_good.y - roi_out->y;
1325 const size_t ioffs = (size_t)(in_dy * ipitch) + (size_t)(in_dx * in_bpp);
1326 const size_t ooffs = (size_t)(out_dy * opitch) + (size_t)(out_dx * out_bpp);
1327
1328 /* origin and region of full input tile */
1329 size_t iorigin[] = { 0, 0, 0 };
1330 size_t iregion[] = { iroi_full.width, iroi_full.height, 1 };
1331
1332 /* origin and region of good part of output tile */
1333 size_t oorigin[] = { oroi_good.x - oroi_full.x, oroi_good.y - oroi_full.y, 0 };
1334 size_t oregion[] = { oroi_good.width, oroi_good.height, 1 };
1335
1336 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_roi] process tile (%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT ") size %dx%d at origin [%d,%d]\n",
1337 tx, ty, iroi_full.width, iroi_full.height, iroi_full.x, iroi_full.y);
1338 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_roi] dest [%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT "] at [%" G_GSIZE_FORMAT ",%" G_GSIZE_FORMAT "], offsets [%i,%i] -> [%i,%i], delta=%i\n\n",
1339 oregion[0], oregion[1], oorigin[0], oorigin[1], in_dx, in_dy, out_dx, out_dy, delta);
1340
1341 /* get opencl input and output buffers */
1342 input = dt_opencl_alloc_device(devid, iroi_full.width, iroi_full.height, in_bpp);
1343 if(IS_NULL_PTR(input)) goto error;
1344
1345 output = dt_opencl_alloc_device(devid, oroi_full.width, oroi_full.height, out_bpp);
1346 if(IS_NULL_PTR(output)) goto error;
1347
1348 /* blocking direct memory transfer: host input image -> opencl/device tile */
1349 err = dt_opencl_write_host_to_device_raw(devid, (char *)ivoid + ioffs, input, iorigin, iregion,
1350 ipitch, CL_TRUE);
1351 if(err != CL_SUCCESS) goto error;
1352
1353 /* call process_cl of module */
1354 dt_dev_pixelpipe_iop_t piece_tile = *piece;
1355 piece_tile.roi_in = iroi_full;
1356 piece_tile.roi_out = oroi_full;
1357 if(!self->process_cl(self, pipe, &piece_tile, input, output)) goto error;
1358
1359 /* blocking direct memory transfer: good part of opencl/device tile -> host output image */
1360 err = dt_opencl_read_host_from_device_raw(devid, (char *)ovoid + ooffs, output, oorigin, oregion,
1361 opitch, CL_TRUE);
1362 if(err != CL_SUCCESS) goto error;
1363
1364 /* release input and output buffers */
1366 input = NULL;
1368 output = NULL;
1369
1370 /* block until opencl queue has finished to free all used event handlers */
1372 }
1373
1376 mutable_pipe->tiling = 0;
1377 return TRUE;
1378
1379error:
1382 mutable_pipe->tiling = 0;
1384 "[default_process_tiling_opencl_roi] couldn't run process_cl() for module '%s' in tiling mode: %i\n",
1385 self->op, err);
1386 return FALSE;
1387}
1388
1389
1390
1391/* if a module does not implement process_tiling_cl() by itself, this function is called instead.
1392 _default_process_tiling_cl_ptp() is able to handle standard cases where pixels do not change their places.
1393 _default_process_tiling_cl_roi() takes care of all other cases where image gets distorted. */
1395 const struct dt_dev_pixelpipe_iop_t *piece,
1396 const void *const ivoid, void *const ovoid, const int in_bpp)
1397{
1398 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1399 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1400 if(memcmp(roi_in, roi_out, sizeof(struct dt_iop_roi_t)) || (self->flags() & IOP_FLAGS_TILING_FULL_ROI))
1401 return _default_process_tiling_cl_roi(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
1402 else
1403 return _default_process_tiling_cl_ptp(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
1404}
1405
1406#else
1407int default_process_tiling_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1408 const struct dt_dev_pixelpipe_iop_t *piece,
1409 const void *const ivoid, void *const ovoid, const int in_bpp)
1410{
1411 (void)pipe;
1412 return FALSE;
1413}
1414#endif
1415
1416
1417/* If a module does not implement tiling_callback() by itself, this function is called instead.
1418 Default is an image size factor of 2 (i.e. input + output buffer needed), no overhead (1),
1419 no overlap between tiles, and an pixel alignment of 1 in x and y direction, i.e. no special
1420 alignment required. Simple pixel to pixel modules (take tonecurve as an example) can happily
1421 live with that.
1422 (1) Small overhead like look-up-tables in tonecurve can be ignored safely. */
1423void default_tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1424 const struct dt_dev_pixelpipe_iop_t *piece,
1426{
1427 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1428 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1429 const float ioratio
1430 = ((float)roi_out->width * (float)roi_out->height) / ((float)roi_in->width * (float)roi_in->height);
1431
1432 tiling->factor = 1.0f + ioratio;
1433 tiling->factor_cl = tiling->factor;
1434 tiling->maxbuf = 1.0f;
1435 tiling->maxbuf_cl = tiling->maxbuf;
1436 tiling->overhead = 0;
1437 tiling->overlap = 0;
1438 tiling->xalign = 1;
1439 tiling->yalign = 1;
1440
1441 if((self->flags() & IOP_FLAGS_TILING_FULL_ROI) == IOP_FLAGS_TILING_FULL_ROI) tiling->overlap = 4;
1442
1443 if(self->iop_order > dt_ioppr_get_iop_order(pipe->iop_order_list, "demosaic", 0)) return;
1444
1445 // all operations that work with mosaiced data should respect pattern size!
1446
1447 if(!piece->dsc_in.filters) return;
1448
1449 if(piece->dsc_in.filters == 9u)
1450 {
1451 // X-Trans, sensor is 6x6 but algorithms have been corrected to work with 3x3
1452 tiling->xalign = 3;
1453 tiling->yalign = 3;
1454 }
1455 else
1456 {
1457 // Bayer, good old 2x2
1458 tiling->xalign = 2;
1459 tiling->yalign = 2;
1460 }
1461
1462 return;
1463}
1464
1465int dt_tiling_piece_fits_host_memory(const size_t width, const size_t height, const unsigned bpp,
1466 const float factor, const size_t overhead)
1467{
1468 const size_t total = factor * width * height * bpp + overhead;
1469
1470 /* The working set lives in the arena and packs into a CONTIGUOUS free run
1471 * (see the cap in the tile planners): measure both the byte headroom and
1472 * the largest run, evicting to make room — eviction merges adjacent free
1473 * runs, but cannot merge across entries pinned by the pipe recursion. */
1474 size_t available = dt_get_available_mem();
1475 size_t largest_run = dt_pixelpipe_cache_get_largest_free_run();
1476
1477 int error = 0;
1478 while(!error && (available < total || (size_t)(0.9f * largest_run) < total))
1479 {
1480 /* Stop evicting once the internal budget headroom already fits: past that
1481 * point the blocker is the system-availability cap inside
1482 * dt_get_available_mem() (issue #1083), which eviction cannot reliably
1483 * raise — freed pages reach the OS asynchronously. Draining the whole
1484 * cache would not change the answer; the caller tiles instead. */
1485 size_t cache_current = 0;
1486 size_t cache_max = 0;
1487 dt_dev_pixelpipe_cache_get_usage(&cache_current, &cache_max);
1488 if(cache_max - cache_current >= total && (size_t)(0.9f * largest_run) >= total) break;
1489
1491 available = dt_get_available_mem();
1493 }
1494
1495 return total <= available && total <= (size_t)(0.9f * largest_run);
1496}
1497
1498// clang-format off
1499// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1500// vim: shiftwidth=2 expandtab tabstop=2 cindent
1501// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1502// clang-format on
static void error(char *msg)
Definition ashift_lsd.c:202
#define TRUE
Definition ashift_lsd.c:162
#define FALSE
Definition ashift_lsd.c:158
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static const float x
const int t
const float delta
size_t dt_get_available_mem()
Definition darktable.c:2386
int bpp
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:190
void *const ovoid
int dt_ioppr_get_iop_order(GList *iop_order_list, const char *op_name, const int multi_priority)
Return the iop_order for a given operation/instance pair.
Definition iop_order.c:913
@ DT_DEBUG_OPENCL
Definition logging.h:57
@ DT_DEBUG_MEMORY
Definition logging.h:59
@ DT_DEBUG_VERBOSE
Definition logging.h:78
@ DT_DEBUG_TILING
Definition logging.h:74
int32_t dt_get_debug_flags(void)
Definition darktable.c:2085
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
void void void dt_vprint(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
dt_print() that additionally requires DT_DEBUG_VERBOSE to be enabled, i.e. both -d <channel> and -d v...
#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
uint32_t width
Definition mipmap_cache.c:0
uint32_t height
Definition mipmap_cache.c:1
static int simplex(double(*objfunc)(double[], void *params), double start[], int n, double EPSILON, double scale, int maxiter, void(*constrain)(double[], int n), void *params)
cl_ulong dt_opencl_get_device_available(const int devid)
Definition opencl.c:3130
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2894
gboolean dt_opencl_get_device_max_image_size(const int devid, int *width, int *height)
Largest 2D image the device will accept, which is what bounds tile size.
Definition opencl.c:2017
int dt_opencl_read_host_from_device_raw(const int devid, void *host, void *device, const size_t *origin, const size_t *region, const int rowpitch, const int blocking)
Definition opencl.c:2622
cl_ulong dt_opencl_get_device_memalloc(const int devid)
Definition opencl.c:3180
gboolean dt_opencl_finish(const int devid)
Definition opencl.c:1671
int dt_opencl_write_host_to_device_raw(const int devid, const void *host, void *device, const size_t *origin, const size_t *region, const int rowpitch, const int blocking)
Definition opencl.c:2667
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2805
#define ROUNDUPDHT(a, b)
Definition opencl.h:86
#define ROUNDUPDWD(a, b)
Definition opencl.h:85
#define __OMP_PARALLEL_FOR__(...)
Definition openmp.h:95
const float factor
Definition pdf.h:91
void dt_pipeline_message(const char *format,...)
Everything the pixel pipeline says to whoever is watching: messages for the user, and the busy banner...
int dt_dev_pixel_pipe_cache_remove_lru(void)
size_t dt_pixelpipe_cache_get_largest_free_run(void)
void dt_dev_pixelpipe_cache_get_usage(size_t *current, size_t *max)
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
#define dt_pixelpipe_cache_free_align(mem)
dt_iop_buffer_dsc_t dsc_out
dt_iop_buffer_dsc_t dsc_in
dt_dev_pixelpipe_type_t type
uint32_t filters
Definition format.h:89
dt_dev_operation_t op
Definition imageop.h:259
Region of interest passed through the pixelpipe.
Definition format.h:49
double scale
Definition format.h:51
int width
Definition format.h:50
int height
Definition format.h:50
typedef double((*spd)(unsigned long int wavelength, double TempK))
#define MIN(a, b)
Definition thinplate.c:32
#define MAX(a, b)
Definition thinplate.c:29
static double _nm_fitness(double x[], void *params)
Definition tiling.c:140
int default_process_tiling(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const int in_bpp)
Definition tiling.c:826
static int _fit_output_to_input_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *iroi, dt_iop_roi_t *oroi, int delta, int iter)
Definition tiling.c:197
static int _nm_fit_output_to_input_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *iroi, dt_iop_roi_t *oroi, int delta)
Definition tiling.c:170
void default_tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, struct dt_develop_tiling_t *tiling)
Definition tiling.c:1423
static int _default_process_tiling_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int in_bpp)
Definition tiling.c:489
static int _align_up(int n, int a)
Definition tiling.c:92
static int _default_process_tiling_ptp(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int in_bpp)
Definition tiling.c:241
static void _print_roi(const dt_iop_roi_t *roi, const char *label)
Definition tiling.c:115
#define RESERVE
Definition tiling.c:59
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
static int _max(int a, int b)
Definition tiling.c:86
static int _default_process_tiling_cl_ptp(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int in_bpp)
Definition tiling.c:842
static int _align_close(int n, int a)
Definition tiling.c:100
static unsigned _lcm(unsigned a, unsigned b)
Definition tiling.c:75
static int _default_process_tiling_cl_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out, const int in_bpp)
Definition tiling.c:1076
static int _min(int a, int b)
Definition tiling.c:81
#define CL_ALIGNMENT
Definition tiling.c:54
int default_process_tiling_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe, const struct dt_dev_pixelpipe_iop_t *piece, const void *const ivoid, void *const ovoid, const int in_bpp)
Definition tiling.c:1394
static int _align_down(int n, int a)
Definition tiling.c:96
static int _maximum_number_tiles()
Definition tiling.c:110
static unsigned _gcd(unsigned a, unsigned b)
Definition tiling.c:62