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