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
35#include "common/darktable.h"
36#include "develop/tiling.h"
37#include "common/opencl.h"
38#include "control/control.h"
39#include "develop/blend.h"
40#include "develop/pixelpipe.h"
42
43#include <assert.h>
44#include <math.h>
45#include <stdlib.h>
46#include <string.h>
47#include <strings.h>
48#include <unistd.h>
49
50#define CLAMPI(a, mn, mx) ((a) < (mn) ? (mn) : ((a) > (mx) ? (mx) : (a)))
51
52
53/* this defines an additional alignment requirement for opencl image width.
54 It can have strong effects on processing speed. Reasonable values are a
55 power of 2. set to 1 for no effect. */
56#define CL_ALIGNMENT ((piece->dsc_in.filters != 9u) ? 4 : 1)
57
58/* parameter RESERVE for extended roi_in sizes due to inaccuracies when doing
59 roi_out -> roi_in estimations.
60 Needs to be increased if tiling fails due to insufficient buffer sizes. */
61#define RESERVE 5
62
63/* greatest common divisor */
64static unsigned _gcd(unsigned a, unsigned b)
65{
66 unsigned t;
67 while(b != 0)
68 {
69 t = b;
70 b = a % b;
71 a = t;
72 }
73 return MAX(a, 1);
74}
75
76/* least common multiple */
77static unsigned _lcm(unsigned a, unsigned b)
78{
79 return (((unsigned long)a * b) / _gcd(a, b));
80}
81
82
83static inline int _min(int a, int b)
84{
85 return a < b ? a : b;
86}
87
88static inline int _max(int a, int b)
89{
90 return a > b ? a : b;
91}
92
93
94static inline int _align_up(int n, int a)
95{
96 return n + a - (n % a);
97}
98static inline int _align_down(int n, int a)
99{
100 return n - (n % a);
101}
102static inline int _align_close(int n, int a)
103{
104 const int off = n % a;
105 const int shift = (off > a/2) ? a - off : -off;
106 return n + shift;
107}
108
109/*
110 Completely arbitrary... Make that a pref ?
111*/
112static inline int _maximum_number_tiles()
113{
114 return 10000;
115}
116
117static inline void _print_roi(const dt_iop_roi_t *roi, const char *label)
118{
120 fprintf(stderr," {%5d %5d ->%5d %5d (%5dx%5d) %.6f } %s\n",
121 roi->x, roi->y, roi->x + roi->width, roi->y + roi->height, roi->width, roi->height, roi->scale, label);
122}
123
124
125#if 0
126static void
127_nm_constraints(double x[], int n)
128{
129 x[0] = fabs(x[0]);
130 x[1] = fabs(x[1]);
131 x[2] = fabs(x[2]);
132 x[3] = fabs(x[3]);
133
134 if(x[0] > 1.0) x[0] = 1.0 - x[0];
135 if(x[1] > 1.0) x[1] = 1.0 - x[1];
136 if(x[2] > 1.0) x[2] = 1.0 - x[2];
137 if(x[3] > 1.0) x[3] = 1.0 - x[3];
138
139}
140#endif
141
142static double _nm_fitness(double x[], void *params)
143{
144 void **rest = (void **)params;
145 struct dt_iop_module_t *self = (struct dt_iop_module_t *)rest[0];
146 const struct dt_dev_pixelpipe_iop_t *piece = (const struct dt_dev_pixelpipe_iop_t *)rest[1];
147 struct dt_iop_roi_t *iroi = (struct dt_iop_roi_t *)rest[2];
148 struct dt_iop_roi_t *oroi = (struct dt_iop_roi_t *)rest[3];
149 const struct dt_dev_pixelpipe_t *pipe = (const struct dt_dev_pixelpipe_t *)rest[4];
150
151 dt_iop_roi_t oroi_test = *oroi;
152 oroi_test.x = x[0] * piece->iwidth;
153 oroi_test.y = x[1] * piece->iheight;
154 oroi_test.width = x[2] * piece->iwidth;
155 oroi_test.height = x[3] * piece->iheight;
156
157 dt_iop_roi_t iroi_probe = *iroi;
158 dt_dev_pixelpipe_iop_t piece_copy = *piece;
159 self->modify_roi_in(self, pipe, &piece_copy, &oroi_test, &iroi_probe);
160
161 double fitness = 0.0;
162
163 fitness += (double)(iroi_probe.x - iroi->x) * (iroi_probe.x - iroi->x);
164 fitness += (double)(iroi_probe.y - iroi->y) * (iroi_probe.y - iroi->y);
165 fitness += (double)(iroi_probe.width - iroi->width) * (iroi_probe.width - iroi->width);
166 fitness += (double)(iroi_probe.height - iroi->height) * (iroi_probe.height - iroi->height);
167
168 return fitness;
169}
170
171
172static int _nm_fit_output_to_input_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
173 const struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *iroi,
174 dt_iop_roi_t *oroi, int delta)
175{
176 void *rest[5] = { (void *)self, (void *)piece, (void *)iroi, (void *)oroi, (void *)pipe };
177 double start[4] = { (float)oroi->x / piece->iwidth, (float)oroi->y / piece->iheight,
178 (float)oroi->width / piece->iwidth, (float)oroi->height / piece->iheight };
179 double epsilon = (double)delta / MIN(piece->iwidth, piece->iheight);
180 int maxiter = 1000;
181
182 int iter = simplex(_nm_fitness, start, 4, epsilon, 1.0, maxiter, NULL, rest);
183
184 dt_vprint(DT_DEBUG_TILING, "[_nm_fit_output_to_input_roi] simplex: %d, delta: %d, epsilon: %f\n", iter, delta, epsilon);
185
186 oroi->x = start[0] * piece->iwidth;
187 oroi->y = start[1] * piece->iheight;
188 oroi->width = start[2] * piece->iwidth;
189 oroi->height = start[3] * piece->iheight;
190
191 return (iter <= maxiter);
192}
193
194
195
196/* find a matching oroi_full by probing start value of oroi and get corresponding input roi into iroi_probe.
197 We search in two steps. first by a simplicistic iterative search which will succeed in most cases.
198 If this does not converge, we do a downhill simplex (nelder-mead) fitting */
199static int _fit_output_to_input_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
200 const struct dt_dev_pixelpipe_iop_t *piece, const dt_iop_roi_t *iroi,
201 dt_iop_roi_t *oroi, int delta, int iter)
202{
203 dt_iop_roi_t iroi_probe = *iroi;
204 dt_iop_roi_t save_oroi = *oroi;
205 dt_dev_pixelpipe_iop_t piece_copy = *piece;
206
207 // try to go the easy way. this works in many cases where output is
208 // just like input, only scaled down
209 self->modify_roi_in(self, pipe, &piece_copy, oroi, &iroi_probe);
210 while((abs((int)iroi_probe.x - (int)iroi->x) > delta || abs((int)iroi_probe.y - (int)iroi->y) > delta
211 || abs((int)iroi_probe.width - (int)iroi->width) > delta
212 || abs((int)iroi_probe.height - (int)iroi->height) > delta) && iter > 0)
213 {
214 _print_roi(&iroi_probe, "tile iroi_probe");
215 _print_roi(oroi, "tile oroi old");
216
217 oroi->x += (iroi->x - iroi_probe.x) * oroi->scale / iroi->scale;
218 oroi->y += (iroi->y - iroi_probe.y) * oroi->scale / iroi->scale;
219 oroi->width += (iroi->width - iroi_probe.width) * oroi->scale / iroi->scale;
220 oroi->height += (iroi->height - iroi_probe.height) * oroi->scale / iroi->scale;
221
222 _print_roi(oroi, "tile oroi new");
223
224 piece_copy = *piece;
225 self->modify_roi_in(self, pipe, &piece_copy, oroi, &iroi_probe);
226 iter--;
227 }
228
229 if(iter > 0) return TRUE;
230
231 *oroi = save_oroi;
232
233 // simplicistic approach did not converge.
234 // try simplex downhill fitting now.
235 // it's crucial that we have a good starting point in oroi, else this
236 // will not converge as well.
237 int fit = _nm_fit_output_to_input_roi(self, pipe, piece, iroi, oroi, delta);
238 return fit;
239}
240
241
242/* simple tiling algorithm for roi_in == roi_out, i.e. for pixel to pixel modules/operations */
243static int _default_process_tiling_ptp(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
244 const struct dt_dev_pixelpipe_iop_t *piece,
245 const void *const ivoid, void *const ovoid,
246 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
247 const int in_bpp)
248{
249 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
250 void *input = NULL;
251 void *output = NULL;
252 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] **** tiling module '%s' for image with size %dx%d --> %dx%d\n",
253 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
254 const int out_bpp = piece->dsc_out.bpp;
255
256 const int ipitch = roi_in->width * in_bpp;
257 const int opitch = roi_out->width * out_bpp;
258 const int max_bpp = _max(in_bpp, out_bpp);
259
260 /* get tiling requirements of module */
262 self->tiling_callback(self, pipe, piece, &tiling);
263
264 /* tiling really does not make sense in these cases. standard process() is not better or worse than we are
265 */
266 if((tiling.factor < 2.2f)
267 && (tiling.overhead < 0.2f * roi_in->width * roi_in->height * max_bpp))
268 {
269 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] no need to use tiling for module '%s' as no real "
270 "memory saving to be expected\n", self->op);
271 goto fallback;
272 }
273
274 /* calculate optimal size of tiles */
275 float available = dt_get_available_mem();
276 assert(available >= 500.0f * 1024.0f * 1024.0f);
277 /* correct for size of ivoid and ovoid which are needed on top of tiling */
278 available = fmaxf(available - ((float)roi_out->width * roi_out->height * out_bpp)
279 - ((float)roi_in->width * roi_in->height * in_bpp) - tiling.overhead,
280 0);
281
282 /* Size the tile from the memory left in the host cache.
283 Using the generic singlebuffer floor here can oversize tiles for modules whose
284 scratch buffers scale with tiling.factor, which defeats tiling and makes the
285 tile-local allocations fail later on. */
286 const float factor = fmaxf(tiling.factor, 1.0f);
287 const float maxbuf = fmaxf(tiling.maxbuf, 1.0f);
288 const float singlebuffer = available / factor;
289
290 int width = roi_in->width;
291 int height = roi_in->height;
292
293 /* shrink tile size in case it would exceed singlebuffer size */
294 if((float)width * height * max_bpp * maxbuf > singlebuffer)
295 {
296 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
297
298 /* TODO: can we make this more efficient to minimize total overlap between tiles? */
299 if(width < height && scale >= 0.333f)
300 {
301 height = floorf(height * scale);
302 }
303 else if(height <= width && scale >= 0.333f)
304 {
305 width = floorf(width * scale);
306 }
307 else
308 {
309 width = floorf(width * sqrtf(scale));
310 height = floorf(height * sqrtf(scale));
311 }
312 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_ptp] buffer exceeds singlebuffer, corrected to %dx%d\n",
313 width, height);
314 }
315
316 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
317 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
318 {
319 width = height = floorf(sqrtf((float)width * height));
320 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_roi] use squares because of overlap, corrected to %dx%d\n",
321 width, height);
322 }
323
324 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
325 Modules will report alignment requirements via xalign and yalign within tiling_callback().
326 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
327 direction.
328 We guarantee alignment by selecting image width/height and overlap accordingly. For a tile width/height
329 that is identical to image width/height no special alignment is needed. */
330
331 const unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
332
333 assert(xyalign != 0);
334
335 /* properly align tile width and height by making them smaller if needed */
336 if(width < roi_in->width) width = (width / xyalign) * xyalign;
337 if(height < roi_in->height) height = (height / xyalign) * xyalign;
338
339 /* also make sure that overlap follows alignment rules by making it wider when needed */
340 const int overlap = tiling.overlap % xyalign != 0 ? (tiling.overlap / xyalign + 1) * xyalign
341 : tiling.overlap;
342
343 /* calculate effective tile size */
344 const int tile_wd = width - 2 * overlap > 0 ? width - 2 * overlap : 1;
345 const int tile_ht = height - 2 * overlap > 0 ? height - 2 * overlap : 1;
346
347 /* calculate number of tiles */
348 const int tiles_x = width < roi_in->width ? ceilf(roi_in->width / (float)tile_wd) : 1;
349 const int tiles_y = height < roi_in->height ? ceilf(roi_in->height / (float)tile_ht) : 1;
350
351 /* sanity check: don't run wild on too many tiles */
352 if(tiles_x * tiles_y > _maximum_number_tiles())
353 {
354 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] gave up tiling for module '%s'. too many tiles: %d x %d\n",
355 self->op, tiles_x, tiles_y);
356 goto error;
357 }
358
359 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] (%dx%d) tiles with max dimensions %dx%d and overlap %d\n",
360 tiles_x, tiles_y, width, height, overlap);
361
362 /* reserve input and output buffers for tiles */
364 (size_t)width * height * in_bpp,
365 pipe->type);
366 if(IS_NULL_PTR(input))
367 {
368 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] could not alloc input buffer for module '%s'\n",
369 self->op);
370 goto error;
371 }
373 (size_t)width * height * out_bpp,
374 pipe->type);
375 if(IS_NULL_PTR(output))
376 {
377 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] could not alloc output buffer for module '%s'\n",
378 self->op);
379 goto error;
380 }
381
382 /* iterate over tiles */
383 for(size_t tx = 0; tx < tiles_x; tx++)
384 {
385 const size_t wd = tx * tile_wd + width > roi_in->width ? roi_in->width - tx * tile_wd : width;
386 for(size_t ty = 0; ty < tiles_y; ty++)
387 {
388 mutable_pipe->tiling = 1;
389
390 const size_t ht = ty * tile_ht + height > roi_in->height ? roi_in->height - ty * tile_ht : height;
391
392 /* no need to process end-tiles that are smaller than the total overlap area */
393 if((wd <= 2 * overlap && tx > 0) || (ht <= 2 * overlap && ty > 0)) continue;
394
395 /* origin and region of effective part of tile, which we want to store later */
396 size_t origin[] = { 0, 0, 0 };
397 size_t region[] = { wd, ht, 1 };
398
399 /* roi_in and roi_out for process_cl on subbuffer */
400 dt_iop_roi_t iroi = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
401 dt_iop_roi_t oroi = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
402
403 /* offsets of tile into ivoid and ovoid */
404 const size_t ioffs = (ty * tile_ht) * ipitch + (tx * tile_wd) * in_bpp;
405 size_t ooffs = (ty * tile_ht) * opitch + (tx * tile_wd) * out_bpp;
406
407 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",
408 tx, ty, wd, ht, tx * tile_wd, ty * tile_ht);
409
410/* prepare input tile buffer */
412 for(size_t j = 0; j < ht; j++)
413 memcpy((char *)input + j * wd * in_bpp, (char *)ivoid + ioffs + j * ipitch, (size_t)wd * in_bpp);
414
415 /* call process() of module */
416 dt_dev_pixelpipe_iop_t piece_tile = *piece;
417 piece_tile.roi_in = iroi;
418 piece_tile.roi_out = oroi;
419 int err = self->process(self, pipe, &piece_tile, input, output);
420 if(err)
421 {
424 mutable_pipe->tiling = 0;
425 return err;
426 }
427
428 /* correct origin and region of tile for overlap.
429 make sure that we only copy back the "good" part. */
430 if(tx > 0)
431 {
432 origin[0] += overlap;
433 region[0] -= overlap;
434 ooffs += (size_t)overlap * out_bpp;
435 }
436 if(ty > 0)
437 {
438 origin[1] += overlap;
439 region[1] -= overlap;
440 ooffs += (size_t)overlap * opitch;
441 }
442
443/* copy "good" part of tile to output buffer */
445 for(size_t j = 0; j < region[1]; j++)
446 memcpy((char *)ovoid + ooffs + j * opitch,
447 (char *)output + ((j + origin[1]) * wd + origin[0]) * out_bpp, (size_t)region[0] * out_bpp);
448 }
449 }
450
453 mutable_pipe->tiling = 0;
454 return 0;
455
456error:
457 dt_control_log(_("tiling failed for module '%s'. output might be garbled."), self->op);
458// fall through
459
460fallback:
463 mutable_pipe->tiling = 0;
464 dt_print(DT_DEBUG_TILING, "[default_process_tiling_ptp] fall back to standard processing for module '%s'\n",
465 self->op);
466 int err = self->process(self, pipe, piece, ivoid, ovoid);
467 return err;
468}
469
470
471
472/* more elaborate tiling algorithm for roi_in != roi_out: slower than the ptp variant,
473 more tiles and larger overlap */
474static int _default_process_tiling_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
475 const struct dt_dev_pixelpipe_iop_t *piece,
476 const void *const ivoid, void *const ovoid,
477 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
478 const int in_bpp)
479{
480 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
481 void *input = NULL;
482 void *output = NULL;
483
484 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] **** tiling module '%s' for image input size %dx%d --> %dx%d\n",
485 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
486 _print_roi(roi_in, "module roi_in");
487 _print_roi(roi_out, "module roi_out");
488
489 const int out_bpp = piece->dsc_out.bpp;
490
491 const int ipitch = roi_in->width * in_bpp;
492 const int opitch = roi_out->width * out_bpp;
493 const int max_bpp = _max(in_bpp, out_bpp);
494
495 float fullscale = fmaxf(roi_in->scale / roi_out->scale, sqrtf(((float)roi_in->width * roi_in->height)
496 / ((float)roi_out->width * roi_out->height)));
497
498 /* inaccuracy for roi_in elements in roi_out -> roi_in calculations */
499 const int delta = ceilf(fullscale);
500
501 /* estimate for additional (space) requirement in buffer dimensions due to inaccuracies */
502 const int inacc = RESERVE * delta;
503
504 /* get tiling requirements of module */
506 self->tiling_callback(self, pipe, piece, &tiling);
507
508 /* tiling really does not make sense in these cases. standard process() is not better or worse than we are
509 */
510 if((tiling.factor < 2.2f && tiling.overhead < 0.2f * roi_in->width * roi_in->height * max_bpp))
511 {
512 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] no need to use tiling for module '%s' as no memory saving is expected\n",
513 self->op);
514 goto fallback;
515 }
516
517 /* calculate optimal size of tiles */
518 float available = dt_get_available_mem();
519 assert(available >= 500.0f * 1024.0f * 1024.0f);
520 /* correct for size of ivoid and ovoid which are needed on top of tiling */
521 available = fmaxf(available - ((float)roi_out->width * roi_out->height * out_bpp)
522 - ((float)roi_in->width * roi_in->height * in_bpp) - tiling.overhead,
523 0);
524
525 /* Size the tile from the memory left in the host cache.
526 Using the generic singlebuffer floor here can oversize tiles for modules whose
527 scratch buffers scale with tiling.factor, which defeats tiling and makes the
528 tile-local allocations fail later on. */
529 const float factor = fmaxf(tiling.factor, 1.0f);
530 const float maxbuf = fmaxf(tiling.maxbuf, 1.0f);
531 const float singlebuffer = available / factor;
532
533 int width = _max(roi_in->width, roi_out->width);
534 int height = _max(roi_in->height, roi_out->height);
535
536 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
537 Modules will report alignment requirements via xalign and yalign within tiling_callback().
538 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
539 direction. */
540
541 /* for simplicity reasons we use only one alignment that fits to x and y requirements at the same time */
542 const unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
543
544 assert(xyalign != 0);
545
546 /* shrink tile size in case it would exceed singlebuffer size */
547 if((float)width * height * max_bpp * maxbuf > singlebuffer)
548 {
549 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
550
551 /* TODO: can we make this more efficient to minimize total overlap between tiles? */
552 if(width < height && scale >= 0.333f)
553 {
554 height = _align_down((int)floorf(height * scale), xyalign);
555 }
556 else if(height <= width && scale >= 0.333f)
557 {
558 width = _align_down((int)floorf(width * scale), xyalign);
559 }
560 else
561 {
562 width = _align_down((int)floorf(width * sqrtf(scale)), xyalign);
563 height = _align_down((int)floorf(height * sqrtf(scale)), xyalign);
564 }
565 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_roi] buffer exceeds singlebuffer, corrected to %dx%d\n",
566 width, height);
567 }
568
569 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
570 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
571 {
572 width = height = _align_down((int)floorf(sqrtf((float)width * height)), xyalign);
573 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_roi] use squares because of overlap, corrected to %dx%d\n",
574 width, height);
575 }
576
577 /* make sure that overlap follows alignment rules by making it wider when needed.
578 overlap_in needs to be aligned, overlap_out is only here to calculate output buffer size */
579 const int overlap_in = _align_up(tiling.overlap, xyalign);
580 const int overlap_out = ceilf((float)overlap_in / fullscale);
581
582 int tiles_x = 1, tiles_y = 1;
583
584 /* calculate number of tiles taking the larger buffer (input or output) as a guiding one.
585 normally it is roi_in > roi_out; but let's be prepared */
586 if(roi_in->width > roi_out->width)
587 tiles_x = width < roi_in->width
588 ? ceilf((float)roi_in->width / (float)_max(width - 2 * overlap_in - inacc, 1))
589 : 1;
590 else
591 tiles_x = width < roi_out->width ? ceilf((float)roi_out->width / (float)_max(width - 2 * overlap_out, 1))
592 : 1;
593
594 if(roi_in->height > roi_out->height)
595 tiles_y = height < roi_in->height
596 ? ceilf((float)roi_in->height / (float)_max(height - 2 * overlap_in - inacc, 1))
597 : 1;
598 else
599 tiles_y = height < roi_out->height
600 ? ceilf((float)roi_out->height / (float)_max(height - 2 * overlap_out, 1))
601 : 1;
602
603 /* sanity check: don't run wild on too many tiles */
604 if(tiles_x * tiles_y > _maximum_number_tiles())
605 {
606 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] gave up tiling for module '%s'. too many tiles: %d x %d\n",
607 self->op, tiles_x, tiles_y);
608 goto error;
609 }
610
611
612 /* calculate tile width and height excl. overlap (i.e. the good part) for output.
613 values are important for all following processing steps. */
614 const int tile_wd = _align_up(
615 roi_out->width % tiles_x == 0 ? roi_out->width / tiles_x : roi_out->width / tiles_x + 1, xyalign);
616 const int tile_ht = _align_up(
617 roi_out->height % tiles_y == 0 ? roi_out->height / tiles_y : roi_out->height / tiles_y + 1, xyalign);
618
619 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] (%dx%d) tiles with max dimensions %dx%d, good %dx%d, overlap %d->%d\n",
620 tiles_x, tiles_y, width, height, tile_wd, tile_ht, overlap_in, overlap_out);
621
622 /* iterate over tiles */
623 for(size_t tx = 0; tx < tiles_x; tx++)
624 for(size_t ty = 0; ty < tiles_y; ty++)
625 {
626 mutable_pipe->tiling = 1;
627
628 /* the output dimensions of the good part of this specific tile */
629 const size_t wd = (tx + 1) * tile_wd > roi_out->width ? (size_t)roi_out->width - tx * tile_wd : tile_wd;
630 const size_t ht = (ty + 1) * tile_ht > roi_out->height ? (size_t)roi_out->height - ty * tile_ht : tile_ht;
631
632 /* roi_in and roi_out of good part: oroi_good easy to calculate based on number and dimension of tile.
633 iroi_good is calculated by modify_roi_in() of respective module */
634 dt_iop_roi_t iroi_good = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
635 dt_iop_roi_t oroi_good = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
636
637 dt_dev_pixelpipe_iop_t piece_copy = *piece;
638 self->modify_roi_in(self, pipe, &piece_copy, &oroi_good, &iroi_good);
639
640 /* clamp iroi_good to not exceed roi_in */
641 iroi_good.x = _max(iroi_good.x, roi_in->x);
642 iroi_good.y = _max(iroi_good.y, roi_in->y);
643 iroi_good.width = _min(iroi_good.width, roi_in->width + roi_in->x - iroi_good.x);
644 iroi_good.height = _min(iroi_good.height, roi_in->height + roi_in->y - iroi_good.y);
645
646 _print_roi(&iroi_good, "tile iroi_good");
647 _print_roi(&oroi_good, "tile oroi_good");
648
649 /* now we need to calculate full region of this tile: increase input roi to take care of overlap
650 requirements
651 and alignment and add additional delta to correct for possible rounding errors in modify_roi_in()
652 -> generates first estimate of iroi_full */
653 const int x_in = iroi_good.x;
654 const int y_in = iroi_good.y;
655 const int width_in = iroi_good.width;
656 const int height_in = iroi_good.height;
657 const int new_x_in = _max(_align_close(x_in - overlap_in - delta, xyalign), roi_in->x);
658 const int new_y_in = _max(_align_close(y_in - overlap_in - delta, xyalign), roi_in->y);
659 const int new_width_in = _min(_align_up(width_in + overlap_in + delta + (x_in - new_x_in), xyalign),
660 roi_in->width + roi_in->x - new_x_in);
661 const int new_height_in = _min(_align_up(height_in + overlap_in + delta + (y_in - new_y_in), xyalign),
662 roi_in->height + roi_in->y - new_y_in);
663
664 /* iroi_full based on calculated numbers and dimensions. oroi_full just set as a starting point for the
665 * following iterative search */
666 dt_iop_roi_t iroi_full = { new_x_in, new_y_in, new_width_in, new_height_in, iroi_good.scale };
667 dt_iop_roi_t oroi_full = oroi_good; // a good starting point for optimization
668
669 _print_roi(&iroi_full, "tile iroi_full before optimization");
670 _print_roi(&oroi_full, "tile oroi_full before optimization");
671
672 /* try to find a matching oroi_full */
673 if(!_fit_output_to_input_roi(self, pipe, piece, &iroi_full, &oroi_full, delta, 10))
674 {
675 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] can not handle requested roi's. tiling for "
676 "module '%s' not possible.\n",
677 self->op);
678 goto error;
679 }
680
681 _print_roi(&iroi_full, "tile iroi_full after optimization");
682 _print_roi(&oroi_full, "tile oroi_full after optimization");
683
684 /* make sure that oroi_full at least covers the range of oroi_good.
685 this step is needed due to the possibility of rounding errors */
686 oroi_full.x = _min(oroi_full.x, oroi_good.x);
687 oroi_full.y = _min(oroi_full.y, oroi_good.y);
688 oroi_full.width = _max(oroi_full.width, oroi_good.x + oroi_good.width - oroi_full.x);
689 oroi_full.height = _max(oroi_full.height, oroi_good.y + oroi_good.height - oroi_full.y);
690
691 /* clamp oroi_full to not exceed roi_out */
692 oroi_full.x = _max(oroi_full.x, roi_out->x);
693 oroi_full.y = _max(oroi_full.y, roi_out->y);
694 oroi_full.width = _min(oroi_full.width, roi_out->width + roi_out->x - oroi_full.x);
695 oroi_full.height = _min(oroi_full.height, roi_out->height + roi_out->y - oroi_full.y);
696
697 /* calculate final iroi_full */
698 dt_dev_pixelpipe_iop_t piece_full = *piece;
699 self->modify_roi_in(self, pipe, &piece_full, &oroi_full, &iroi_full);
700
701 /* clamp iroi_full to not exceed roi_in */
702 iroi_full.x = _max(iroi_full.x, roi_in->x);
703 iroi_full.y = _max(iroi_full.y, roi_in->y);
704 iroi_full.width = _min(iroi_full.width, roi_in->width + roi_in->x - iroi_full.x);
705 iroi_full.height = _min(iroi_full.height, roi_in->height + roi_in->y - iroi_full.y);
706
707 _print_roi(&iroi_full, "tile iroi_full final");
708 _print_roi(&oroi_full, "tile oroi_full final");
709
710 /* offsets of tile into ivoid and ovoid */
711 const size_t ioffs = ((size_t)iroi_full.y - roi_in->y) * ipitch + ((size_t)iroi_full.x - roi_in->x) * in_bpp;
712 size_t ooffs = ((size_t)oroi_good.y - roi_out->y) * opitch + ((size_t)oroi_good.x - roi_out->x) * out_bpp;
713
714 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",
715 tx, ty, iroi_full.width, iroi_full.height, iroi_full.x, iroi_full.y);
716
717 /* prepare input tile buffer */
719 (size_t)iroi_full.width * iroi_full.height * in_bpp,
720 pipe->type);
721 if(IS_NULL_PTR(input))
722 {
723 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] could not alloc input buffer for module '%s'\n",
724 self->op);
725 goto error;
726 }
728 (size_t)oroi_full.width * oroi_full.height * out_bpp,
729 pipe->type);
730 if(IS_NULL_PTR(output))
731 {
732 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] could not alloc output buffer for module '%s'\n",
733 self->op);
734 goto error;
735 }
737 for(size_t j = 0; j < iroi_full.height; j++)
738 memcpy((char *)input + j * iroi_full.width * in_bpp, (char *)ivoid + ioffs + j * ipitch,
739 (size_t)iroi_full.width * in_bpp);
740
741 /* call process() of module */
742 dt_dev_pixelpipe_iop_t piece_tile = *piece;
743 piece_tile.roi_in = iroi_full;
744 piece_tile.roi_out = oroi_full;
745 int err = self->process(self, pipe, &piece_tile, input, output);
746 if(err)
747 {
750 mutable_pipe->tiling = 0;
751 return err;
752 }
753
754 /* copy "good" part of tile to output buffer */
755 const int origin_x = oroi_good.x - oroi_full.x;
756 const int origin_y = oroi_good.y - oroi_full.y;
758 for(size_t j = 0; j < oroi_good.height; j++)
759 memcpy((char *)ovoid + ooffs + j * opitch,
760 (char *)output + ((j + origin_y) * oroi_full.width + origin_x) * out_bpp,
761 (size_t)oroi_good.width * out_bpp);
762
765 input = output = NULL;
766 }
767
770 mutable_pipe->tiling = 0;
771 return 0;
772
773error:
774 dt_control_log(_("tiling failed for module '%s'. output might be garbled."), self->op);
775// fall through
776
777fallback:
780 mutable_pipe->tiling = 0;
781 dt_print(DT_DEBUG_TILING, "[default_process_tiling_roi] fall back to standard processing for module '%s'\n",
782 self->op);
783 int err = self->process(self, pipe, piece, ivoid, ovoid);
784 return err;
785}
786
787
788
789/* if a module does not implement process_tiling() by itself, this function is called instead.
790 _default_process_tiling_ptp() is able to handle standard cases where pixels do not change their places.
791 _default_process_tiling_roi() takes care of all other cases where image gets distorted and for module
792 "clipping",
793 "flip" as this may flip or mirror the image. */
794int default_process_tiling(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
795 const struct dt_dev_pixelpipe_iop_t *piece,
796 const void *const ivoid, void *const ovoid, const int in_bpp)
797{
798 const dt_iop_roi_t *const roi_in = &piece->roi_in;
799 const dt_iop_roi_t *const roi_out = &piece->roi_out;
800 if(memcmp(roi_in, roi_out, sizeof(struct dt_iop_roi_t)) || (self->flags() & IOP_FLAGS_TILING_FULL_ROI))
801 return _default_process_tiling_roi(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
802 else
803 return _default_process_tiling_ptp(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
804}
805
806
807
808#ifdef HAVE_OPENCL
809/* simple tiling algorithm for roi_in == roi_out, i.e. for pixel to pixel modules/operations */
810static int _default_process_tiling_cl_ptp(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
811 const struct dt_dev_pixelpipe_iop_t *piece,
812 const void *const ivoid, void *const ovoid,
813 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
814 const int in_bpp)
815{
816 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
817 cl_int err = -999;
818 cl_mem input = NULL;
819 cl_mem output = NULL;
820
821 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] **** tiling module '%s' for image with size %dx%d --> %dx%d\n",
822 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
823
824 const int out_bpp = piece->dsc_out.bpp;
825
826 const int devid = pipe->devid;
827 const int ipitch = roi_in->width * in_bpp;
828 const int opitch = roi_out->width * out_bpp;
829 const int max_bpp = _max(in_bpp, out_bpp);
830
831 /* get tiling requirements of module */
833 self->tiling_callback(self, pipe, piece, &tiling);
834
835 // avoid problems when pinned buffer size gets too close to max_mem_alloc size
836 const float available = (float)dt_opencl_get_device_available(devid);
837 const float factor = fmaxf(tiling.factor_cl, 1.0f);
838 const float singlebuffer = fminf(fmaxf((available - tiling.overhead) / factor, 0.0f),
840 const float maxbuf = fmaxf(tiling.maxbuf_cl, 1.0f);
843
844 /* shrink tile size in case it would exceed singlebuffer size */
845 if((float)width * height * max_bpp * maxbuf > singlebuffer)
846 {
847 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
848
849 if(width < height && scale >= 0.333f)
850 {
851 height = floorf(height * scale);
852 }
853 else if(height <= width && scale >= 0.333f)
854 {
855 width = floorf(width * scale);
856 }
857 else
858 {
859 width = floorf(width * sqrtf(scale));
860 height = floorf(height * sqrtf(scale));
861 }
862 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] buffer exceeds singlebuffer, corrected to %dx%d\n",
863 width, height);
864 }
865
866 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
867 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
868 {
869 width = height = floorf(sqrtf((float)width * height));
870 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] use squares because of overlap, corrected to %dx%d\n",
871 width, height);
872 }
873
874 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
875 Modules will report alignment requirements via xalign and yalign within tiling_callback().
876 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
877 direction. Additional alignment requirements are set via definition of CL_ALIGNMENT.
878 We guarantee alignment by selecting image width/height and overlap accordingly. For a tile width/height
879 that is identical to image width/height no special alignment is done. */
880
881 /* for simplicity reasons we use only one alignment that fits to x and y requirements at the same time */
882 const unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
883
884 /* determining alignment requirement for tile width/height.
885 in case of tile width also align according to definition of CL_ALIGNMENT */
886 const unsigned int walign = _lcm(xyalign, CL_ALIGNMENT);
887 const unsigned int halign = xyalign;
888
889 assert(xyalign != 0 && walign != 0 && halign != 0);
890
891 /* properly align tile width and height by making them smaller if needed */
892 if(width < roi_in->width) width = (width / walign) * walign;
893 if(height < roi_in->height) height = (height / halign) * halign;
894
895 /* OpenCL image allocations are backed by device-specific row/height strides.
896 The generic full-frame pre-check already reasons on rounded dimensions, so
897 tiling needs to use the same planning rule or it may pick a tile that fits
898 mathematically in width*height*bpp but still fails once the driver rounds it
899 up internally. Shrink the candidate tile until the rounded image footprint
900 fits the per-buffer budget. */
901 while((float)ROUNDUPDWD(width, devid) * ROUNDUPDHT(height, devid) * max_bpp * maxbuf > singlebuffer)
902 {
903 if(width <= (int)walign && height <= (int)halign) break;
904 if(width < height && height > (int)halign)
905 height -= halign;
906 else if(width > (int)walign)
907 width -= walign;
908 else
909 height -= halign;
910 }
911
912 /* also make sure that overlap follows alignment rules by making it wider when needed */
913 const int overlap = tiling.overlap % xyalign != 0 ? (tiling.overlap / xyalign + 1) * xyalign
914 : tiling.overlap;
915
916
917 /* calculate effective tile size */
918 const int tile_wd = width - 2 * overlap > 0 ? width - 2 * overlap : 1;
919 const int tile_ht = height - 2 * overlap > 0 ? height - 2 * overlap : 1;
920
921
922 /* calculate number of tiles */
923 const int tiles_x = width < roi_in->width ? ceilf(roi_in->width / (float)tile_wd) : 1;
924 const int tiles_y = height < roi_in->height ? ceilf(roi_in->height / (float)tile_ht) : 1;
925
926 /* sanity check: don't run wild on too many tiles */
927 if(tiles_x * tiles_y > _maximum_number_tiles())
928 {
929 dt_print(DT_DEBUG_TILING, "[default_process_tiling_cl_ptp] aborted tiling for module '%s'. too many tiles: %d x %d\n",
930 self->op, tiles_x, tiles_y);
931 return FALSE;
932 }
933
934 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",
935 tiles_x, tiles_y, width, height, tile_wd, tile_ht, overlap);
936
937 /* iterate over tiles */
938 for(size_t tx = 0; tx < tiles_x; tx++)
939 for(size_t ty = 0; ty < tiles_y; ty++)
940 {
941 mutable_pipe->tiling = 1;
942
943 const size_t wd = tx * tile_wd + width > roi_in->width ? roi_in->width - tx * tile_wd : width;
944 const size_t ht = ty * tile_ht + height > roi_in->height ? roi_in->height - ty * tile_ht : height;
945
946 /* no need to process (end)tiles that are smaller than the total overlap area */
947 if((wd <= 2 * overlap && tx > 0) || (ht <= 2 * overlap && ty > 0)) continue;
948
949 /* origin and region of effective part of tile, which we want to store later */
950 size_t origin[] = { 0, 0, 0 };
951 size_t region[] = { wd, ht, 1 };
952
953 /* roi_in and roi_out for process_cl on subbuffer */
954 dt_iop_roi_t iroi = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
955 dt_iop_roi_t oroi = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
956
957
958 /* offsets of tile into ivoid and ovoid */
959 const size_t ioffs = (ty * tile_ht) * ipitch + (tx * tile_wd) * in_bpp;
960 size_t ooffs = (ty * tile_ht) * opitch + (tx * tile_wd) * out_bpp;
961
962
963 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",
964 tx, ty, wd, ht, tx * tile_wd, ty * tile_ht);
965
966 /* get input and output buffers */
967 input = dt_opencl_alloc_device(devid, wd, ht, in_bpp);
968 if(IS_NULL_PTR(input)) goto error;
969 output = dt_opencl_alloc_device(devid, wd, ht, out_bpp);
970 if(IS_NULL_PTR(output)) goto error;
971
972 /* blocking direct memory transfer: host input image -> opencl/device tile */
973 err = dt_opencl_write_host_to_device_raw(devid, (char *)ivoid + ioffs, input, origin, region, ipitch,
974 CL_TRUE);
975 if(err != CL_SUCCESS) goto error;
976
977 /* call process_cl of module */
978 dt_dev_pixelpipe_iop_t piece_tile = *piece;
979 piece_tile.roi_in = iroi;
980 piece_tile.roi_out = oroi;
981 if(!self->process_cl(self, pipe, &piece_tile, input, output)) goto error;
982
983 /* correct origin and region of tile for overlap.
984 makes sure that we only copy back the "good" part. */
985 if(tx > 0)
986 {
987 origin[0] += overlap;
988 region[0] -= overlap;
989 ooffs += (size_t)overlap * out_bpp;
990 }
991 if(ty > 0)
992 {
993 origin[1] += overlap;
994 region[1] -= overlap;
995 ooffs += (size_t)overlap * opitch;
996 }
997
998 /* blocking direct memory transfer: good part of opencl/device tile -> host output image */
999 err = dt_opencl_read_host_from_device_raw(devid, (char *)ovoid + ooffs, output, origin, region,
1000 opitch, CL_TRUE);
1001 if(err != CL_SUCCESS) goto error;
1002
1003 /* release input and output buffers */
1005 input = NULL;
1007 output = NULL;
1008
1009 /* block until opencl queue has finished to free all used event handlers */
1011 }
1012
1015 mutable_pipe->tiling = 0;
1016 return TRUE;
1017
1018error:
1021 mutable_pipe->tiling = 0;
1023 "[default_process_tiling_opencl_ptp] couldn't run process_cl() for module '%s' in tiling mode: %i\n",
1024 self->op, err);
1025 return FALSE;
1026}
1027
1028
1029/* more elaborate tiling algorithm for roi_in != roi_out: slower than the ptp variant,
1030 more tiles and larger overlap */
1031static int _default_process_tiling_cl_roi(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1032 const struct dt_dev_pixelpipe_iop_t *piece,
1033 const void *const ivoid, void *const ovoid,
1034 const dt_iop_roi_t *const roi_in, const dt_iop_roi_t *const roi_out,
1035 const int in_bpp)
1036{
1037 dt_dev_pixelpipe_t *const mutable_pipe = (dt_dev_pixelpipe_t *)pipe;
1038 cl_int err = -999;
1039 cl_mem input = NULL;
1040 cl_mem output = NULL;
1041
1043 "[default_process_tiling_cl_roi] **** tiling module '%s' for image with input size %dx%d --> %dx%d\n",
1044 self->op, roi_in->width, roi_in->height, roi_out->width, roi_out->height);
1045 _print_roi(roi_in, "module roi_in");
1046 _print_roi(roi_out, "module roi_out");
1047
1048 const int out_bpp = piece->dsc_out.bpp;
1049
1050 const int devid = pipe->devid;
1051 const int ipitch = roi_in->width * in_bpp;
1052 const int opitch = roi_out->width * out_bpp;
1053 const int max_bpp = _max(in_bpp, out_bpp);
1054
1055 const float fullscale = fmaxf(roi_in->scale / roi_out->scale, sqrtf(((float)roi_in->width * roi_in->height)
1056 / ((float)roi_out->width * roi_out->height)));
1057
1058 /* inaccuracy for roi_in elements in roi_out -> roi_in calculations */
1059 const int delta = ceilf(fullscale);
1060
1061 /* estimate for additional (space) requirement in buffer dimensions due to inaccuracies */
1062 const int inacc = RESERVE * delta;
1063
1064 /* get tiling requirements of module */
1066 self->tiling_callback(self, pipe, piece, &tiling);
1067
1068 // avoid problems when pinned buffer size gets too close to max_mem_alloc size
1069 const float available = (float)dt_opencl_get_device_available(devid);
1070 const float factor = fmaxf(tiling.factor_cl, 1.0f);
1071 const float singlebuffer = fminf(fmaxf((available - tiling.overhead) / factor, 0.0f),
1073 const float maxbuf = fmaxf(tiling.maxbuf_cl, 1.0f);
1074
1075 int width = _min(_max(roi_in->width, roi_out->width), darktable.opencl->dev[devid].max_image_width);
1076 int height = _min(_max(roi_in->height, roi_out->height), darktable.opencl->dev[devid].max_image_height);
1077
1078 /* Alignment rules: we need to make sure that alignment requirements of module are fulfilled.
1079 Modules will report alignment requirements via xalign and yalign within tiling_callback().
1080 Typical use case is demosaic where Bayer pattern requires alignment to a multiple of 2 in x and y
1081 direction. Additional alignment requirements are set via definition of CL_ALIGNMENT. */
1082
1083 /* for simplicity reasons we use only one alignment that fits to x and y requirements at the same time */
1084 unsigned int xyalign = _lcm(tiling.xalign, tiling.yalign);
1085 xyalign = _lcm(xyalign, CL_ALIGNMENT);
1086
1087 assert(xyalign != 0);
1088
1089 /* shrink tile size in case it would exceed singlebuffer size */
1090 if((float)width * height * max_bpp * maxbuf > singlebuffer)
1091 {
1092 const float scale = singlebuffer / ((float)width * height * max_bpp * maxbuf);
1093
1094 if(width < height && scale >= 0.333f)
1095 {
1096 height = _align_down((int)floorf(height * scale), xyalign);
1097 }
1098 else if(height <= width && scale >= 0.333f)
1099 {
1100 width = _align_down((int)floorf(width * scale), xyalign);
1101 }
1102 else
1103 {
1104 width = _align_down((int)floorf(width * sqrtf(scale)), xyalign);
1105 height = _align_down((int)floorf(height * sqrtf(scale)), xyalign);
1106 }
1107 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_roi] buffer exceeds singlebuffer, corrected to %dx%d\n",
1108 width, height);
1109 }
1110
1111 /* make sure we have a reasonably effective tile dimension. if not try square tiles */
1112 if(3 * tiling.overlap > width || 3 * tiling.overlap > height)
1113 {
1114 width = height = _align_down((int)floorf(sqrtf((float)width * height)), xyalign);
1115 dt_vprint(DT_DEBUG_TILING, "[default_process_tiling_cl_roi] use squares because of overlap, corrected to %dx%d\n",
1116 width, height);
1117 }
1118
1119 /* make sure that overlap follows alignment rules by making it wider when needed.
1120 overlap_in needs to be aligned, overlap_out is only here to calculate output buffer size */
1121 const int overlap_in = _align_up(tiling.overlap, xyalign);
1122 const int overlap_out = ceilf((float)overlap_in / fullscale);
1123
1124 /* As in the pixel-perfect tiler above, keep planning conservative with the
1125 same rounded OpenCL dimensions used by the non-tiling GPU fit checks. The
1126 ROI path can otherwise accept a tile whose raw area fits `singlebuffer`
1127 even though the driver-backed image allocation for the tile does not. */
1128 while((float)ROUNDUPDWD(width, devid) * ROUNDUPDHT(height, devid) * max_bpp * maxbuf > singlebuffer)
1129 {
1130 if(width <= (int)xyalign && height <= (int)xyalign) break;
1131 if(width < height && height > (int)xyalign)
1132 height -= xyalign;
1133 else if(width > (int)xyalign)
1134 width -= xyalign;
1135 else
1136 height -= xyalign;
1137 }
1138
1139 int tiles_x = 1, tiles_y = 1;
1140
1141 /* calculate number of tiles taking the larger buffer (input or output) as a guiding one.
1142 normally it is roi_in > roi_out; but let's be prepared */
1143 if(roi_in->width > roi_out->width)
1144 tiles_x = width < roi_in->width
1145 ? ceilf((float)roi_in->width / (float)_max(width - 2 * overlap_in - inacc, 1))
1146 : 1;
1147 else
1148 tiles_x = width < roi_out->width ? ceilf((float)roi_out->width / (float)_max(width - 2 * overlap_out, 1))
1149 : 1;
1150
1151 if(roi_in->height > roi_out->height)
1152 tiles_y = height < roi_in->height
1153 ? ceilf((float)roi_in->height / (float)_max(height - 2 * overlap_in - inacc, 1))
1154 : 1;
1155 else
1156 tiles_y = height < roi_out->height
1157 ? ceilf((float)roi_out->height / (float)_max(height - 2 * overlap_out, 1))
1158 : 1;
1159
1160 /* sanity check: don't run wild on too many tiles */
1161 if(tiles_x * tiles_y > _maximum_number_tiles())
1162 {
1164 "[default_process_tiling_cl_roi] aborted tiling for module '%s'. too many tiles: %dx%d\n",
1165 self->op, tiles_x, tiles_y);
1166 return FALSE;
1167 }
1168
1169 /* calculate tile width and height excl. overlap (i.e. the good part) for output.
1170 important for all following processing steps. */
1171 const int tile_wd = _align_up(
1172 roi_out->width % tiles_x == 0 ? roi_out->width / tiles_x : roi_out->width / tiles_x + 1, xyalign);
1173 const int tile_ht = _align_up(
1174 roi_out->height % tiles_y == 0 ? roi_out->height / tiles_y : roi_out->height / tiles_y + 1, xyalign);
1175
1177 "[default_process_tiling_cl_roi] (%dx%d) tiles with max input dimensions %dx%d, good %ix%i\n",
1178 tiles_x, tiles_y, width, height, tile_wd, tile_ht);
1179
1180 /* iterate over tiles */
1181 for(size_t tx = 0; tx < tiles_x; tx++)
1182 for(size_t ty = 0; ty < tiles_y; ty++)
1183 {
1184 mutable_pipe->tiling = 1;
1185
1186 /* the output dimensions of the good part of this specific tile */
1187 const size_t wd = (tx + 1) * tile_wd > roi_out->width ? (size_t)roi_out->width - tx * tile_wd : tile_wd;
1188 const size_t ht = (ty + 1) * tile_ht > roi_out->height ? (size_t)roi_out->height - ty * tile_ht : tile_ht;
1189
1190 /* roi_in and roi_out of good part: oroi_good easy to calculate based on number and dimension of tile.
1191 iroi_good is calculated by modify_roi_in() of respective module */
1192 dt_iop_roi_t iroi_good = { roi_in->x + tx * tile_wd, roi_in->y + ty * tile_ht, wd, ht, roi_in->scale };
1193 dt_iop_roi_t oroi_good = { roi_out->x + tx * tile_wd, roi_out->y + ty * tile_ht, wd, ht, roi_out->scale };
1194
1195 dt_dev_pixelpipe_iop_t piece_copy = *piece;
1196 self->modify_roi_in(self, pipe, &piece_copy, &oroi_good, &iroi_good);
1197
1198 /* clamp iroi_good to not exceed roi_in */
1199 iroi_good.x = _max(iroi_good.x, roi_in->x);
1200 iroi_good.y = _max(iroi_good.y, roi_in->y);
1201 iroi_good.width = _min(iroi_good.width, roi_in->width + roi_in->x - iroi_good.x);
1202 iroi_good.height = _min(iroi_good.height, roi_in->height + roi_in->y - iroi_good.y);
1203
1204 _print_roi(&iroi_good, "tile iroi_good");
1205 _print_roi(&oroi_good, "tile oroi_good");
1206
1207 /* now we need to calculate full region of this tile: increase input roi to take care of overlap
1208 requirements
1209 and alignment and add additional delta to correct for possible rounding errors in modify_roi_in()
1210 -> generates first estimate of iroi_full */
1211 const int x_in = iroi_good.x;
1212 const int y_in = iroi_good.y;
1213 const int width_in = iroi_good.width;
1214 const int height_in = iroi_good.height;
1215 const int new_x_in = _max(_align_close(x_in - overlap_in - delta, xyalign), roi_in->x);
1216 const int new_y_in = _max(_align_close(y_in - overlap_in - delta, xyalign), roi_in->y);
1217 const int new_width_in = _min(_align_up(width_in + overlap_in + delta + (x_in - new_x_in), xyalign),
1218 roi_in->width + roi_in->x - new_x_in);
1219 const int new_height_in = _min(_align_up(height_in + overlap_in + delta + (y_in - new_y_in), xyalign),
1220 roi_in->height + roi_in->y - new_y_in);
1221
1222 /* iroi_full based on calculated numbers and dimensions. oroi_full just set as a starting point for the
1223 * following iterative search */
1224 dt_iop_roi_t iroi_full = { new_x_in, new_y_in, new_width_in, new_height_in, iroi_good.scale };
1225 dt_iop_roi_t oroi_full = oroi_good; // a good starting point for optimization
1226
1227 _print_roi(&iroi_full, "tile iroi_full before optimization");
1228 _print_roi(&oroi_full, "tile oroi_full before optimization");
1229
1230 /* try to find a matching oroi_full */
1231 if(!_fit_output_to_input_roi(self, pipe, piece, &iroi_full, &oroi_full, delta, 10))
1232 {
1233 dt_print(DT_DEBUG_OPENCL | DT_DEBUG_TILING, "[default_process_tiling_cl_roi] can not handle requested roi's tiling "
1234 "for module '%s' not possible.\n",
1235 self->op);
1236 goto error;
1237 }
1238
1239
1240 /* make sure that oroi_full at least covers the range of oroi_good.
1241 this step is needed due to the possibility of rounding errors */
1242 oroi_full.x = _min(oroi_full.x, oroi_good.x);
1243 oroi_full.y = _min(oroi_full.y, oroi_good.y);
1244 oroi_full.width = _max(oroi_full.width, oroi_good.x + oroi_good.width - oroi_full.x);
1245 oroi_full.height = _max(oroi_full.height, oroi_good.y + oroi_good.height - oroi_full.y);
1246
1247 /* clamp oroi_full to not exceed roi_out */
1248 oroi_full.x = _max(oroi_full.x, roi_out->x);
1249 oroi_full.y = _max(oroi_full.y, roi_out->y);
1250 oroi_full.width = _min(oroi_full.width, roi_out->width + roi_out->x - oroi_full.x);
1251 oroi_full.height = _min(oroi_full.height, roi_out->height + roi_out->y - oroi_full.y);
1252
1253
1254 /* calculate final iroi_full */
1255 dt_dev_pixelpipe_iop_t piece_full = *piece;
1256 self->modify_roi_in(self, pipe, &piece_full, &oroi_full, &iroi_full);
1257
1258 /* clamp iroi_full to not exceed roi_in */
1259 iroi_full.x = _max(iroi_full.x, roi_in->x);
1260 iroi_full.y = _max(iroi_full.y, roi_in->y);
1261 iroi_full.width = _min(iroi_full.width, roi_in->width + roi_in->x - iroi_full.x);
1262 iroi_full.height = _min(iroi_full.height, roi_in->height + roi_in->y - iroi_full.y);
1263
1264 _print_roi(&iroi_full, "tile iroi_full");
1265 _print_roi(&oroi_full, "tile oroi_full");
1266
1267 /* offsets of tile into ivoid and ovoid */
1268 const int in_dx = iroi_full.x - roi_in->x;
1269 const int in_dy = iroi_full.y - roi_in->y;
1270 const int out_dx = oroi_good.x - roi_out->x;
1271 const int out_dy = oroi_good.y - roi_out->y;
1272 const size_t ioffs = (size_t)(in_dy * ipitch) + (size_t)(in_dx * in_bpp);
1273 const size_t ooffs = (size_t)(out_dy * opitch) + (size_t)(out_dx * out_bpp);
1274
1275 /* origin and region of full input tile */
1276 size_t iorigin[] = { 0, 0, 0 };
1277 size_t iregion[] = { iroi_full.width, iroi_full.height, 1 };
1278
1279 /* origin and region of good part of output tile */
1280 size_t oorigin[] = { oroi_good.x - oroi_full.x, oroi_good.y - oroi_full.y, 0 };
1281 size_t oregion[] = { oroi_good.width, oroi_good.height, 1 };
1282
1283 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",
1284 tx, ty, iroi_full.width, iroi_full.height, iroi_full.x, iroi_full.y);
1285 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",
1286 oregion[0], oregion[1], oorigin[0], oorigin[1], in_dx, in_dy, out_dx, out_dy, delta);
1287
1288 /* get opencl input and output buffers */
1289 input = dt_opencl_alloc_device(devid, iroi_full.width, iroi_full.height, in_bpp);
1290 if(IS_NULL_PTR(input)) goto error;
1291
1292 output = dt_opencl_alloc_device(devid, oroi_full.width, oroi_full.height, out_bpp);
1293 if(IS_NULL_PTR(output)) goto error;
1294
1295 /* blocking direct memory transfer: host input image -> opencl/device tile */
1296 err = dt_opencl_write_host_to_device_raw(devid, (char *)ivoid + ioffs, input, iorigin, iregion,
1297 ipitch, CL_TRUE);
1298 if(err != CL_SUCCESS) goto error;
1299
1300 /* call process_cl of module */
1301 dt_dev_pixelpipe_iop_t piece_tile = *piece;
1302 piece_tile.roi_in = iroi_full;
1303 piece_tile.roi_out = oroi_full;
1304 if(!self->process_cl(self, pipe, &piece_tile, input, output)) goto error;
1305
1306 /* blocking direct memory transfer: good part of opencl/device tile -> host output image */
1307 err = dt_opencl_read_host_from_device_raw(devid, (char *)ovoid + ooffs, output, oorigin, oregion,
1308 opitch, CL_TRUE);
1309 if(err != CL_SUCCESS) goto error;
1310
1311 /* release input and output buffers */
1313 input = NULL;
1315 output = NULL;
1316
1317 /* block until opencl queue has finished to free all used event handlers */
1319 }
1320
1323 mutable_pipe->tiling = 0;
1324 return TRUE;
1325
1326error:
1329 mutable_pipe->tiling = 0;
1331 "[default_process_tiling_opencl_roi] couldn't run process_cl() for module '%s' in tiling mode: %i\n",
1332 self->op, err);
1333 return FALSE;
1334}
1335
1336
1337
1338/* if a module does not implement process_tiling_cl() by itself, this function is called instead.
1339 _default_process_tiling_cl_ptp() is able to handle standard cases where pixels do not change their places.
1340 _default_process_tiling_cl_roi() takes care of all other cases where image gets distorted. */
1342 const struct dt_dev_pixelpipe_iop_t *piece,
1343 const void *const ivoid, void *const ovoid, const int in_bpp)
1344{
1345 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1346 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1347 if(memcmp(roi_in, roi_out, sizeof(struct dt_iop_roi_t)) || (self->flags() & IOP_FLAGS_TILING_FULL_ROI))
1348 return _default_process_tiling_cl_roi(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
1349 else
1350 return _default_process_tiling_cl_ptp(self, pipe, piece, ivoid, ovoid, roi_in, roi_out, in_bpp);
1351}
1352
1353#else
1354int default_process_tiling_cl(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1355 const struct dt_dev_pixelpipe_iop_t *piece,
1356 const void *const ivoid, void *const ovoid, const int in_bpp)
1357{
1358 (void)pipe;
1359 return FALSE;
1360}
1361#endif
1362
1363
1364/* If a module does not implement tiling_callback() by itself, this function is called instead.
1365 Default is an image size factor of 2 (i.e. input + output buffer needed), no overhead (1),
1366 no overlap between tiles, and an pixel alignment of 1 in x and y direction, i.e. no special
1367 alignment required. Simple pixel to pixel modules (take tonecurve as an example) can happily
1368 live with that.
1369 (1) Small overhead like look-up-tables in tonecurve can be ignored safely. */
1370void default_tiling_callback(struct dt_iop_module_t *self, const struct dt_dev_pixelpipe_t *pipe,
1371 const struct dt_dev_pixelpipe_iop_t *piece,
1373{
1374 const dt_iop_roi_t *const roi_in = &piece->roi_in;
1375 const dt_iop_roi_t *const roi_out = &piece->roi_out;
1376 const float ioratio
1377 = ((float)roi_out->width * (float)roi_out->height) / ((float)roi_in->width * (float)roi_in->height);
1378
1379 tiling->factor = 1.0f + ioratio;
1380 tiling->factor_cl = tiling->factor;
1381 tiling->maxbuf = 1.0f;
1382 tiling->maxbuf_cl = tiling->maxbuf;
1383 tiling->overhead = 0;
1384 tiling->overlap = 0;
1385 tiling->xalign = 1;
1386 tiling->yalign = 1;
1387
1388 if((self->flags() & IOP_FLAGS_TILING_FULL_ROI) == IOP_FLAGS_TILING_FULL_ROI) tiling->overlap = 4;
1389
1390 if(self->iop_order > dt_ioppr_get_iop_order(pipe->iop_order_list, "demosaic", 0)) return;
1391
1392 // all operations that work with mosaiced data should respect pattern size!
1393
1394 if(!piece->dsc_in.filters) return;
1395
1396 if(piece->dsc_in.filters == 9u)
1397 {
1398 // X-Trans, sensor is 6x6 but algorithms have been corrected to work with 3x3
1399 tiling->xalign = 3;
1400 tiling->yalign = 3;
1401 }
1402 else
1403 {
1404 // Bayer, good old 2x2
1405 tiling->xalign = 2;
1406 tiling->yalign = 2;
1407 }
1408
1409 return;
1410}
1411
1412int dt_tiling_piece_fits_host_memory(const size_t width, const size_t height, const unsigned bpp,
1413 const float factor, const size_t overhead)
1414{
1415 size_t available = dt_get_available_mem();
1416 const size_t total = factor * width * height * bpp + overhead;
1417
1418 // Try to make room in cache first
1419 int error = 0;
1420 while(!error && available < total)
1421 {
1423 available = dt_get_available_mem();
1424 }
1425
1426 if(total <= available)
1427 return TRUE;
1428 else
1429 return FALSE;
1430}
1431
1432// clang-format off
1433// modelines: These editor modelines have been set for all relevant files by tools/update_modelines.py
1434// vim: shiftwidth=2 expandtab tabstop=2 cindent
1435// kate: tab-indents: off; indent-width 2; replace-tabs on; indent-mode cstyle; remove-trailing-spaces modified;
1436// 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
int width
Definition bilateral.h:1
int height
Definition bilateral.h:1
const float delta
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
void dt_control_log(const char *msg,...)
Definition control.c:777
void dt_vprint(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1625
darktable_t darktable
Definition darktable.c:183
size_t dt_get_available_mem()
Definition darktable.c:1740
void dt_print(dt_debug_thread_t thread, const char *msg,...)
Definition darktable.c:1600
@ DT_DEBUG_OPENCL
Definition darktable.h:744
@ DT_DEBUG_VERBOSE
Definition darktable.h:765
@ DT_DEBUG_TILING
Definition darktable.h:761
#define dt_pixelpipe_cache_alloc_align_cache(size, id)
Definition darktable.h:445
#define dt_pixelpipe_cache_free_align(mem)
Definition darktable.h:475
#define __OMP_PARALLEL_FOR__(...)
Definition darktable.h:270
#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 darktable.h:293
int bpp
@ IOP_FLAGS_TILING_FULL_ROI
Definition imageop.h:201
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:867
static const float x
const int t
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:2740
void * dt_opencl_alloc_device(const int devid, const int width, const int height, const int bpp)
Definition opencl.c:2504
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:2232
cl_ulong dt_opencl_get_device_memalloc(const int devid)
Definition opencl.c:2753
gboolean dt_opencl_finish(const int devid)
Definition opencl.c:1375
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:2277
void dt_opencl_release_mem_object(cl_mem mem)
Definition opencl.c:2415
#define ROUNDUPDHT(a, b)
Definition opencl.h:82
#define ROUNDUPDWD(a, b)
Definition opencl.h:81
const float factor
Definition pdf.h:90
int dt_dev_pixel_pipe_cache_remove_lru(dt_dev_pixelpipe_cache_t *cache)
struct dt_dev_pixelpipe_cache_t * pixelpipe_cache
Definition darktable.h:818
struct dt_opencl_t * opencl
Definition darktable.h:813
int32_t unmuted
Definition darktable.h:788
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:60
GModule *dt_dev_operation_t op
Definition imageop.h:286
Region of interest passed through the pixelpipe.
Definition imageop.h:72
double scale
Definition imageop.h:74
size_t max_image_width
Definition opencl.h:141
size_t max_image_height
Definition opencl.h:142
dt_opencl_device_t * dev
Definition opencl.h:273
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:142
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:794
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:199
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:172
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:1370
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:474
static int _align_up(int n, int a)
Definition tiling.c:94
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:243
static void _print_roi(const dt_iop_roi_t *roi, const char *label)
Definition tiling.c:117
#define RESERVE
Definition tiling.c:61
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:1412
static int _max(int a, int b)
Definition tiling.c:88
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:810
static int _align_close(int n, int a)
Definition tiling.c:102
static unsigned _lcm(unsigned a, unsigned b)
Definition tiling.c:77
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:1031
static int _min(int a, int b)
Definition tiling.c:83
#define CL_ALIGNMENT
Definition tiling.c:56
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:1341
static int _align_down(int n, int a)
Definition tiling.c:98
static int _maximum_number_tiles()
Definition tiling.c:112
static unsigned _gcd(unsigned a, unsigned b)
Definition tiling.c:64