1 /* This file is part of GEGL.
2 *
3 * This library is free software; you can redistribute it and/or
4 * modify it under the terms of the GNU Lesser General Public
5 * License as published by the Free Software Foundation; either
6 * version 3 of the License, or (at your option) any later version.
7 *
8 * This library is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
11 * Lesser General Public License for more details.
12 *
13 * You should have received a copy of the GNU Lesser General Public
14 * License along with this library; if not, see <https://www.gnu.org/licenses/>.
15 *
16 * Copyright 2006-2012,2014-2017 Øyvind Kolås <pippin@gimp.org>
17 * 2013 Daniel Sabo
18 */
19
20 #include "config.h"
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdint.h>
24 #include <math.h>
25
26 #include <glib-object.h>
27 #include <glib/gprintf.h>
28 #include <gio/gio.h>
29
30 #include <babl/babl.h>
31 #include "gegl-algorithms.h"
32 #include "gegl-buffer-types.h"
33 #include "gegl-buffer.h"
34 #include "gegl-buffer-private.h"
35 #include "gegl-tile-storage.h"
36 #include "gegl-tile-handler-empty.h"
37 #include "gegl-sampler.h"
38 #include "gegl-tile-backend.h"
39 #include "gegl-buffer-iterator.h"
40 #include "gegl-rectangle.h"
41 #include "gegl-buffer-iterator-private.h"
42 #include "gegl-buffer-formats.h"
43
44 static void gegl_buffer_iterate_read_fringed (GeglBuffer *buffer,
45 const GeglRectangle *roi,
46 const GeglRectangle *abyss,
47 guchar *buf,
48 gint buf_stride,
49 const Babl *format,
50 gint level,
51 GeglAbyssPolicy repeat_mode);
52
53
54 static void gegl_buffer_iterate_read_dispatch (GeglBuffer *buffer,
55 const GeglRectangle *roi,
56 guchar *buf,
57 gint rowstride,
58 const Babl *format,
59 gint level,
60 GeglAbyssPolicy repeat_mode);
61
62 static void inline
gegl_buffer_get_pixel(GeglBuffer * buffer,gint x,gint y,const Babl * format,gpointer data,GeglAbyssPolicy repeat_mode)63 gegl_buffer_get_pixel (GeglBuffer *buffer,
64 gint x,
65 gint y,
66 const Babl *format,
67 gpointer data,
68 GeglAbyssPolicy repeat_mode)
69 {
70 const GeglRectangle *abyss = &buffer->abyss;
71 guchar *buf = data;
72
73 if (G_UNLIKELY (y < abyss->y ||
74 x < abyss->x ||
75 y >= abyss->y + abyss->height ||
76 x >= abyss->x + abyss->width))
77 {
78 switch (repeat_mode)
79 {
80 case GEGL_ABYSS_CLAMP:
81 x = CLAMP (x, abyss->x, abyss->x+abyss->width-1);
82 y = CLAMP (y, abyss->y, abyss->y+abyss->height-1);
83 break;
84
85 case GEGL_ABYSS_LOOP:
86 x = abyss->x + GEGL_REMAINDER (x - abyss->x, abyss->width);
87 y = abyss->y + GEGL_REMAINDER (y - abyss->y, abyss->height);
88 break;
89
90 case GEGL_ABYSS_BLACK:
91 {
92 gfloat color[4] = {0.0, 0.0, 0.0, 1.0};
93 babl_process (babl_fish (gegl_babl_rgba_linear_float (), format),
94 color,
95 buf,
96 1);
97 return;
98 }
99
100 case GEGL_ABYSS_WHITE:
101 {
102 gfloat color[4] = {1.0, 1.0, 1.0, 1.0};
103 babl_process (babl_fish (gegl_babl_rgba_linear_float (),
104 format),
105 color,
106 buf,
107 1);
108 return;
109 }
110
111 default:
112 case GEGL_ABYSS_NONE:
113 memset (buf, 0x00, babl_format_get_bytes_per_pixel (format));
114 return;
115 }
116 }
117
118 {
119 gint tile_width = buffer->tile_width;
120 gint tile_height = buffer->tile_height;
121 gint tiledy = y + buffer->shift_y;
122 gint tiledx = x + buffer->shift_x;
123 gint indice_x = gegl_tile_indice (tiledx, tile_width);
124 gint indice_y = gegl_tile_indice (tiledy, tile_height);
125
126 GeglTile *tile = gegl_tile_storage_steal_hot_tile (buffer->tile_storage);
127
128 if (!(tile &&
129 tile->x == indice_x &&
130 tile->y == indice_y))
131 {
132 g_rec_mutex_lock (&buffer->tile_storage->mutex);
133
134 if (tile)
135 gegl_tile_unref (tile);
136
137 tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
138 indice_x, indice_y,
139 0);
140
141 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
142 }
143
144 if (tile)
145 {
146 gint tile_origin_x = indice_x * tile_width;
147 gint tile_origin_y = indice_y * tile_height;
148 gint offsetx = tiledx - tile_origin_x;
149 gint offsety = tiledy - tile_origin_y;
150 gint px_size = babl_format_get_bytes_per_pixel (buffer->soft_format);
151 guchar *tp;
152
153 gegl_tile_read_lock (tile);
154
155 tp = gegl_tile_get_data (tile) +
156 (offsety * tile_width + offsetx) * px_size;
157
158 if (G_UNLIKELY (format != buffer->soft_format))
159 {
160 babl_process (babl_fish (buffer->soft_format, format), tp, buf, 1);
161 }
162 else
163 {
164 memcpy (buf, tp, px_size);
165 }
166
167 gegl_tile_read_unlock (tile);
168
169 gegl_tile_storage_take_hot_tile (buffer->tile_storage, tile);
170 }
171 }
172 }
173
174 static inline void
__gegl_buffer_set_pixel(GeglBuffer * buffer,gint x,gint y,const Babl * format,gconstpointer data)175 __gegl_buffer_set_pixel (GeglBuffer *buffer,
176 gint x,
177 gint y,
178 const Babl *format,
179 gconstpointer data)
180 {
181 const GeglRectangle *abyss = &buffer->abyss;
182 const guchar *buf = data;
183
184 if (G_UNLIKELY (y < abyss->y ||
185 x < abyss->x ||
186 y >= abyss->y + abyss->height ||
187 x >= abyss->x + abyss->width))
188 return;
189
190
191 {
192 gint tile_width = buffer->tile_width;
193 gint tile_height = buffer->tile_height;
194 gint tiledy = y + buffer->shift_y;
195 gint tiledx = x + buffer->shift_x;
196 gint indice_x = gegl_tile_indice (tiledx, tile_width);
197 gint indice_y = gegl_tile_indice (tiledy, tile_height);
198
199 GeglTile *tile = gegl_tile_storage_steal_hot_tile (buffer->tile_storage);
200 const Babl *fish = NULL;
201 gint px_size;
202
203 if (G_UNLIKELY (format != buffer->soft_format))
204 {
205 fish = babl_fish (format, buffer->soft_format);
206 px_size = babl_format_get_bytes_per_pixel (buffer->soft_format);
207 }
208 else
209 {
210 px_size = babl_format_get_bytes_per_pixel (buffer->soft_format);
211 }
212
213 if (!(tile &&
214 tile->x == indice_x &&
215 tile->y == indice_y))
216 {
217 g_rec_mutex_lock (&buffer->tile_storage->mutex);
218
219 if (tile)
220 gegl_tile_unref (tile);
221
222 tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
223 indice_x, indice_y,
224 0);
225
226 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
227 }
228
229 if (tile)
230 {
231 gint tile_origin_x = indice_x * tile_width;
232 gint tile_origin_y = indice_y * tile_height;
233 gint offsetx = tiledx - tile_origin_x;
234 gint offsety = tiledy - tile_origin_y;
235
236 guchar *tp;
237 gegl_tile_lock (tile);
238 tp = gegl_tile_get_data (tile) + (offsety * tile_width + offsetx) * px_size;
239
240 if (fish)
241 babl_process (fish, buf, tp, 1);
242 else
243 memcpy (tp, buf, px_size);
244
245 gegl_tile_unlock (tile);
246
247 gegl_tile_storage_take_hot_tile (buffer->tile_storage, tile);
248 }
249 }
250
251 }
252
253 enum _GeglBufferSetFlag {
254 GEGL_BUFFER_SET_FLAG_FAST = 0,
255 GEGL_BUFFER_SET_FLAG_LOCK = 1<<0,
256 GEGL_BUFFER_SET_FLAG_NOTIFY = 1<<1,
257 GEGL_BUFFER_SET_FLAG_FULL = GEGL_BUFFER_SET_FLAG_LOCK |
258 GEGL_BUFFER_SET_FLAG_NOTIFY
259 };
260
261 typedef enum _GeglBufferSetFlag GeglBufferSetFlag;
262
263 void
264 gegl_buffer_set_with_flags (GeglBuffer *buffer,
265 const GeglRectangle *rect,
266 gint level,
267 const Babl *format,
268 const void *src,
269 gint rowstride,
270 GeglBufferSetFlag set_flags);
271
272
273 static inline void
_gegl_buffer_set_pixel(GeglBuffer * buffer,gint x,gint y,const Babl * format,gconstpointer data,GeglBufferSetFlag flags)274 _gegl_buffer_set_pixel (GeglBuffer *buffer,
275 gint x,
276 gint y,
277 const Babl *format,
278 gconstpointer data,
279 GeglBufferSetFlag flags)
280 {
281 GeglRectangle rect = {x,y,1,1};
282 switch (flags)
283 {
284 case GEGL_BUFFER_SET_FLAG_FAST:
285 __gegl_buffer_set_pixel (buffer, x, y, format, data);
286 break;
287 case GEGL_BUFFER_SET_FLAG_LOCK:
288 gegl_buffer_lock (buffer);
289 __gegl_buffer_set_pixel (buffer, x, y, format, data);
290 gegl_buffer_unlock (buffer);
291 break;
292 case GEGL_BUFFER_SET_FLAG_NOTIFY:
293 __gegl_buffer_set_pixel (buffer, x, y, format, data);
294 gegl_buffer_emit_changed_signal (buffer, &rect);
295 break;
296 case GEGL_BUFFER_SET_FLAG_LOCK|GEGL_BUFFER_SET_FLAG_NOTIFY:
297 default:
298 gegl_buffer_lock (buffer);
299 __gegl_buffer_set_pixel (buffer, x, y, format, data);
300 gegl_buffer_unlock (buffer);
301 gegl_buffer_emit_changed_signal (buffer, &rect);
302 break;
303 }
304 }
305
306 /* flush any unwritten data (flushes the hot-cache of a single
307 * tile used by gegl_buffer_set for 1x1 pixel sized rectangles
308 */
309 void
gegl_buffer_flush(GeglBuffer * buffer)310 gegl_buffer_flush (GeglBuffer *buffer)
311 {
312 GeglTileBackend *backend;
313
314 g_return_if_fail (GEGL_IS_BUFFER (buffer));
315 backend = gegl_buffer_backend (buffer);
316
317 g_rec_mutex_lock (&buffer->tile_storage->mutex);
318
319 _gegl_buffer_drop_hot_tile (buffer);
320
321 if (backend)
322 gegl_tile_backend_set_extent (backend, &buffer->extent);
323
324 gegl_tile_source_command (GEGL_TILE_SOURCE (buffer),
325 GEGL_TILE_FLUSH, 0,0,0,NULL);
326
327 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
328 }
329
330 void
gegl_buffer_flush_ext(GeglBuffer * buffer,const GeglRectangle * rect)331 gegl_buffer_flush_ext (GeglBuffer *buffer, const GeglRectangle *rect)
332 {
333 if (gegl_buffer_ext_flush)
334 gegl_buffer_ext_flush (buffer, rect);
335 }
336
337
338
339 static inline void
gegl_buffer_iterate_write(GeglBuffer * buffer,const GeglRectangle * roi,guchar * buf,gint rowstride,const Babl * format,gint level)340 gegl_buffer_iterate_write (GeglBuffer *buffer,
341 const GeglRectangle *roi,
342 guchar *buf,
343 gint rowstride,
344 const Babl *format,
345 gint level)
346 {
347 gint tile_width = buffer->tile_storage->tile_width;
348 gint tile_height = buffer->tile_storage->tile_height;
349 gint px_size = babl_format_get_bytes_per_pixel (buffer->soft_format);
350 gint bpx_size = babl_format_get_bytes_per_pixel (format);
351 gint tile_stride = px_size * tile_width;
352 gint buf_stride;
353 gint bufy = 0;
354
355 gint buffer_shift_x = buffer->shift_x;
356 gint buffer_shift_y = buffer->shift_y;
357
358 gint width = buffer->extent.width;
359 gint height = buffer->extent.height;
360 gint buffer_x = buffer->extent.x + buffer_shift_x;
361 gint buffer_y = buffer->extent.y + buffer_shift_y;
362
363 gint buffer_abyss_x = buffer->abyss.x + buffer_shift_x;
364 gint buffer_abyss_y = buffer->abyss.y + buffer_shift_y;
365 gint abyss_x_total = buffer_abyss_x + buffer->abyss.width;
366 gint abyss_y_total = buffer_abyss_y + buffer->abyss.height;
367 gint factor = 1<<level;
368 const Babl *fish;
369 GeglRectangle scaled_rect;
370 if (G_UNLIKELY (level && roi))
371 {
372 scaled_rect = *roi;
373 scaled_rect.x <<= level;
374 scaled_rect.y <<= level;
375 scaled_rect.width <<= level;
376 scaled_rect.height <<= level;
377 roi = &scaled_rect;
378 }
379
380 /* roi specified, override buffers extent */
381 if (roi)
382 {
383 width = roi->width;
384 height = roi->height;
385 buffer_x = roi->x + buffer_shift_x;
386 buffer_y = roi->y + buffer_shift_y;
387 }
388
389 buffer_shift_x /= factor;
390 buffer_shift_y /= factor;
391 buffer_abyss_x /= factor;
392 buffer_abyss_y /= factor;
393 abyss_x_total /= factor;
394 abyss_y_total /= factor;
395 buffer_x /= factor;
396 buffer_y /= factor;
397 width /= factor;
398 height /= factor;
399
400
401 buf_stride = width * bpx_size;
402 if (rowstride != GEGL_AUTO_ROWSTRIDE)
403 buf_stride = rowstride;
404
405 if (G_LIKELY (format == buffer->soft_format))
406 {
407 fish = NULL;
408 }
409 else
410 fish = babl_fish ((gpointer) format,
411 (gpointer) buffer->soft_format);
412
413 while (bufy < height)
414 {
415 gint tiledy = buffer_y + bufy;
416 gint offsety = gegl_tile_offset (tiledy, tile_height);
417 gint bufx = 0;
418
419 while (bufx < width)
420 {
421 gint tiledx = buffer_x + bufx;
422 gint offsetx = gegl_tile_offset (tiledx, tile_width);
423 gint y = bufy;
424 gint index_x;
425 gint index_y;
426 gint lskip, rskip, pixels, row;
427 guchar *bp, *tile_base, *tp;
428 GeglTile *tile;
429 gboolean whole_tile;
430
431 bp = buf + (gsize) bufy * buf_stride + bufx * bpx_size;
432
433 if (G_UNLIKELY (width + offsetx - bufx < tile_width))
434 pixels = (width + offsetx - bufx) - offsetx;
435 else
436 pixels = tile_width - offsetx;
437
438 index_x = gegl_tile_indice (tiledx, tile_width);
439 index_y = gegl_tile_indice (tiledy, tile_height);
440
441 lskip = (buffer_abyss_x) - (buffer_x + bufx);
442 /* gap between left side of tile, and abyss */
443 rskip = (buffer_x + bufx + pixels) - abyss_x_total;
444 /* gap between right side of tile, and abyss */
445
446 if (G_UNLIKELY (lskip < 0))
447 lskip = 0;
448 if (G_UNLIKELY (lskip > pixels))
449 lskip = pixels;
450 if (G_UNLIKELY (rskip < 0))
451 rskip = 0;
452 if (G_UNLIKELY (rskip > pixels))
453 rskip = pixels;
454
455 pixels -= lskip;
456 pixels -= rskip;
457
458 whole_tile = pixels == tile_width && bufy >= buffer_abyss_y &&
459 MIN (MIN (height - bufy, tile_height - offsety),
460 abyss_y_total - bufy) == tile_height;
461
462 g_rec_mutex_lock (&buffer->tile_storage->mutex);
463
464 tile = gegl_tile_handler_get_tile ((GeglTileHandler *) buffer,
465 index_x, index_y, level,
466 ! whole_tile);
467
468 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
469
470 if (!tile)
471 {
472 g_warning ("didn't get tile, trying to continue");
473 bufx += (tile_width - offsetx);
474 continue;
475 }
476
477 gegl_tile_lock (tile);
478
479 tile_base = gegl_tile_get_data (tile);
480 tp = ((guchar *) tile_base) + (offsety * tile_width + offsetx) * px_size;
481
482 if (G_UNLIKELY (fish))
483 {
484 int bskip, skip = 0;
485 int rows = MIN(height - bufy, tile_height - offsety);
486
487 bskip = (buffer_y + bufy + rows) - abyss_y_total;
488 bskip = CLAMP (bskip, 0, rows);
489 rows -= bskip;
490
491 /*
492 XXX XXX XXX
493 Making the abyss geometry handling work with babl_process_rows is proving a bit
494 tricky - the choice that skips the skipping at the start of a batch entering a
495 tile seem to let all expected code paths work and no reported non-working code
496 paths yet. This will also be a slight performance loss - but it might be that
497 we seldom do writes that fall in the abyss anyways.
498
499 Not writing into the abyss will permit better control over sliced rendering
500 with multi-threading - and should be added back later.
501
502 */
503
504 #if 0
505 skip = buffer_abyss_y - bufy;
506 if (skip < 0)
507 skip = 0;
508 rows-=skip;
509 #endif
510 if (rows==1)
511 babl_process (fish,bp + lskip * bpx_size + skip * buf_stride, tp + lskip * px_size + skip * tile_stride, pixels);
512 else if (rows>0)
513 babl_process_rows (fish,
514 bp + lskip * bpx_size + skip * buf_stride,
515 buf_stride,
516 tp + lskip * px_size + skip * tile_stride,
517 tile_stride,
518 pixels,
519 rows);
520 }
521 else
522 {
523 int lskip_offset = lskip * px_size;
524
525 #ifdef __GNUC__
526 #define CHECK_ALIGNMENT_ALIGNOF __alignof__
527 #else
528 #define CHECK_ALIGNMENT_ALIGNOF(type) \
529 (G_STRUCT_OFFSET (struct alignof_helper, b))
530 #endif
531 #define CHECK_ALIGNMENT(type) \
532 do \
533 { \
534 struct alignof_helper { char a; type b; }; \
535 /* verify 'alignof (type)' is a power of 2 */ \
536 G_STATIC_ASSERT (! (CHECK_ALIGNMENT_ALIGNOF (type) & \
537 (CHECK_ALIGNMENT_ALIGNOF (type) - 1)));\
538 if ((((uintptr_t) tp + lskip_offset) | \
539 ((uintptr_t) bp + lskip_offset) | \
540 tile_stride | \
541 buf_stride) & \
542 (CHECK_ALIGNMENT_ALIGNOF (type) - 1)) \
543 { \
544 goto unaligned; \
545 } \
546 } \
547 while (FALSE)
548
549 switch (pixels * px_size)
550 {
551 case 1:
552 CHECK_ALIGNMENT (guchar);
553 for (row = offsety;
554 row < tile_height && y < height;
555 row++, y++)
556 {
557 if (buffer_y + y >= buffer_abyss_y &&
558 buffer_y + y < abyss_y_total)
559 {
560 tp[lskip_offset] = bp[lskip_offset];
561 }
562 tp += tile_stride;
563 bp += buf_stride;
564 }
565 break;
566 case 2:
567 CHECK_ALIGNMENT (uint16_t);
568 for (row = offsety;
569 row < tile_height && y < height;
570 row++, y++)
571 {
572 if (buffer_y + y >= buffer_abyss_y &&
573 buffer_y + y < abyss_y_total)
574 {
575 ((uint16_t*)(&tp[lskip_offset]))[0] =
576 ((uint16_t*)(&bp[lskip_offset]))[0];
577 }
578 tp += tile_stride;
579 bp += buf_stride;
580 }
581 break;
582 case 3:
583 CHECK_ALIGNMENT (guchar);
584 for (row = offsety;
585 row < tile_height && y < height;
586 row++, y++)
587 {
588 if (buffer_y + y >= buffer_abyss_y &&
589 buffer_y + y < abyss_y_total)
590 {
591 tp[lskip_offset] = bp[lskip_offset];
592 tp[lskip_offset+1] = bp[lskip_offset+1];
593 tp[lskip_offset+2] = bp[lskip_offset+2];
594 }
595 tp += tile_stride;
596 bp += buf_stride;
597 }
598 break;
599 case 4:
600 CHECK_ALIGNMENT (uint32_t);
601 for (row = offsety;
602 row < tile_height && y < height;
603 row++, y++)
604 {
605 if (buffer_y + y >= buffer_abyss_y &&
606 buffer_y + y < abyss_y_total)
607 {
608 ((uint32_t*)(&tp[lskip_offset]))[0] =
609 ((uint32_t*)(&bp[lskip_offset]))[0];
610 }
611 tp += tile_stride;
612 bp += buf_stride;
613 }
614 break;
615 case 6:
616 CHECK_ALIGNMENT (uint16_t);
617 for (row = offsety;
618 row < tile_height && y < height;
619 row++, y++)
620 {
621 if (buffer_y + y >= buffer_abyss_y &&
622 buffer_y + y < abyss_y_total)
623 {
624 ((uint16_t*)(&tp[lskip_offset]))[0] =
625 ((uint16_t*)(&bp[lskip_offset]))[0];
626 ((uint16_t*)(&tp[lskip_offset]))[1] =
627 ((uint16_t*)(&bp[lskip_offset]))[1];
628 ((uint16_t*)(&tp[lskip_offset]))[2] =
629 ((uint16_t*)(&bp[lskip_offset]))[2];
630 }
631 tp += tile_stride;
632 bp += buf_stride;
633 }
634 break;
635 case 8:
636 CHECK_ALIGNMENT (uint64_t);
637 for (row = offsety;
638 row < tile_height && y < height;
639 row++, y++)
640 {
641 if (buffer_y + y >= buffer_abyss_y &&
642 buffer_y + y < abyss_y_total)
643 {
644 ((uint64_t*)(&tp[lskip_offset]))[0] =
645 ((uint64_t*)(&bp[lskip_offset]))[0];
646 }
647 tp += tile_stride;
648 bp += buf_stride;
649 }
650 break;
651 case 12:
652 CHECK_ALIGNMENT (uint32_t);
653 for (row = offsety;
654 row < tile_height && y < height;
655 row++, y++)
656 {
657 if (buffer_y + y >= buffer_abyss_y &&
658 buffer_y + y < abyss_y_total)
659 {
660 ((uint32_t*)(&tp[lskip_offset]))[0] =
661 ((uint32_t*)(&bp[lskip_offset]))[0];
662 ((uint32_t*)(&tp[lskip_offset]))[1] =
663 ((uint32_t*)(&bp[lskip_offset]))[1];
664 ((uint32_t*)(&tp[lskip_offset]))[2] =
665 ((uint32_t*)(&bp[lskip_offset]))[2];
666 }
667 tp += tile_stride;
668 bp += buf_stride;
669 }
670 break;
671 case 16:
672 CHECK_ALIGNMENT (uint64_t);
673 for (row = offsety;
674 row < tile_height && y < height;
675 row++, y++)
676 {
677 if (buffer_y + y >= buffer_abyss_y &&
678 buffer_y + y < abyss_y_total)
679 {
680 ((uint64_t*)(&tp[lskip_offset]))[0] =
681 ((uint64_t*)(&bp[lskip_offset]))[0];
682 ((uint64_t*)(&tp[lskip_offset]))[1] =
683 ((uint64_t*)(&bp[lskip_offset]))[1];
684 }
685 tp += tile_stride;
686 bp += buf_stride;
687 }
688 break;
689 case 24:
690 CHECK_ALIGNMENT (uint64_t);
691 for (row = offsety;
692 row < tile_height && y < height;
693 row++, y++)
694 {
695 if (buffer_y + y >= buffer_abyss_y &&
696 buffer_y + y < abyss_y_total)
697 {
698 ((uint64_t*)(&tp[lskip_offset]))[0] =
699 ((uint64_t*)(&bp[lskip_offset]))[0];
700 ((uint64_t*)(&tp[lskip_offset]))[1] =
701 ((uint64_t*)(&bp[lskip_offset]))[1];
702 ((uint64_t*)(&tp[lskip_offset]))[2] =
703 ((uint64_t*)(&bp[lskip_offset]))[2];
704 }
705 tp += tile_stride;
706 bp += buf_stride;
707 }
708 break;
709 case 32:
710 CHECK_ALIGNMENT (uint64_t);
711 for (row = offsety;
712 row < tile_height && y < height;
713 row++, y++)
714 {
715 if (buffer_y + y >= buffer_abyss_y &&
716 buffer_y + y < abyss_y_total)
717 {
718 ((uint64_t*)(&tp[lskip_offset]))[0] =
719 ((uint64_t*)(&bp[lskip_offset]))[0];
720 ((uint64_t*)(&tp[lskip_offset]))[1] =
721 ((uint64_t*)(&bp[lskip_offset]))[1];
722 ((uint64_t*)(&tp[lskip_offset]))[2] =
723 ((uint64_t*)(&bp[lskip_offset]))[2];
724 ((uint64_t*)(&tp[lskip_offset]))[3] =
725 ((uint64_t*)(&bp[lskip_offset]))[3];
726 }
727 tp += tile_stride;
728 bp += buf_stride;
729 }
730 break;
731 case 40:
732 CHECK_ALIGNMENT (uint64_t);
733 for (row = offsety;
734 row < tile_height && y < height;
735 row++, y++)
736 {
737 if (buffer_y + y >= buffer_abyss_y &&
738 buffer_y + y < abyss_y_total)
739 {
740 ((uint64_t*)(&tp[lskip_offset]))[0] =
741 ((uint64_t*)(&bp[lskip_offset]))[0];
742 ((uint64_t*)(&tp[lskip_offset]))[1] =
743 ((uint64_t*)(&bp[lskip_offset]))[1];
744 ((uint64_t*)(&tp[lskip_offset]))[2] =
745 ((uint64_t*)(&bp[lskip_offset]))[2];
746 ((uint64_t*)(&tp[lskip_offset]))[3] =
747 ((uint64_t*)(&bp[lskip_offset]))[3];
748 ((uint64_t*)(&tp[lskip_offset]))[4] =
749 ((uint64_t*)(&bp[lskip_offset]))[4];
750 }
751 tp += tile_stride;
752 bp += buf_stride;
753 }
754 break;
755 case 48:
756 CHECK_ALIGNMENT (uint64_t);
757 for (row = offsety;
758 row < tile_height && y < height;
759 row++, y++)
760 {
761 if (buffer_y + y >= buffer_abyss_y &&
762 buffer_y + y < abyss_y_total)
763 {
764 ((uint64_t*)(&tp[lskip_offset]))[0] =
765 ((uint64_t*)(&bp[lskip_offset]))[0];
766 ((uint64_t*)(&tp[lskip_offset]))[1] =
767 ((uint64_t*)(&bp[lskip_offset]))[1];
768 ((uint64_t*)(&tp[lskip_offset]))[2] =
769 ((uint64_t*)(&bp[lskip_offset]))[2];
770 ((uint64_t*)(&tp[lskip_offset]))[3] =
771 ((uint64_t*)(&bp[lskip_offset]))[3];
772 ((uint64_t*)(&tp[lskip_offset]))[4] =
773 ((uint64_t*)(&bp[lskip_offset]))[4];
774 ((uint64_t*)(&tp[lskip_offset]))[5] =
775 ((uint64_t*)(&bp[lskip_offset]))[5];
776 }
777 tp += tile_stride;
778 bp += buf_stride;
779 }
780 break;
781 case 56:
782 CHECK_ALIGNMENT (uint64_t);
783 for (row = offsety;
784 row < tile_height && y < height;
785 row++, y++)
786 {
787 if (buffer_y + y >= buffer_abyss_y &&
788 buffer_y + y < abyss_y_total)
789 {
790 ((uint64_t*)(&tp[lskip_offset]))[0] =
791 ((uint64_t*)(&bp[lskip_offset]))[0];
792 ((uint64_t*)(&tp[lskip_offset]))[1] =
793 ((uint64_t*)(&bp[lskip_offset]))[1];
794 ((uint64_t*)(&tp[lskip_offset]))[2] =
795 ((uint64_t*)(&bp[lskip_offset]))[2];
796 ((uint64_t*)(&tp[lskip_offset]))[3] =
797 ((uint64_t*)(&bp[lskip_offset]))[3];
798 ((uint64_t*)(&tp[lskip_offset]))[4] =
799 ((uint64_t*)(&bp[lskip_offset]))[4];
800 ((uint64_t*)(&tp[lskip_offset]))[5] =
801 ((uint64_t*)(&bp[lskip_offset]))[5];
802 ((uint64_t*)(&tp[lskip_offset]))[6] =
803 ((uint64_t*)(&bp[lskip_offset]))[6];
804 }
805 tp += tile_stride;
806 bp += buf_stride;
807 }
808 break;
809 case 64:
810 CHECK_ALIGNMENT (uint64_t);
811 for (row = offsety;
812 row < tile_height && y < height;
813 row++, y++)
814 {
815 if (buffer_y + y >= buffer_abyss_y &&
816 buffer_y + y < abyss_y_total)
817 {
818 ((uint64_t*)(&tp[lskip_offset]))[0] =
819 ((uint64_t*)(&bp[lskip_offset]))[0];
820 ((uint64_t*)(&tp[lskip_offset]))[1] =
821 ((uint64_t*)(&bp[lskip_offset]))[1];
822 ((uint64_t*)(&tp[lskip_offset]))[2] =
823 ((uint64_t*)(&bp[lskip_offset]))[2];
824 ((uint64_t*)(&tp[lskip_offset]))[3] =
825 ((uint64_t*)(&bp[lskip_offset]))[3];
826 ((uint64_t*)(&tp[lskip_offset]))[4] =
827 ((uint64_t*)(&bp[lskip_offset]))[4];
828 ((uint64_t*)(&tp[lskip_offset]))[5] =
829 ((uint64_t*)(&bp[lskip_offset]))[5];
830 ((uint64_t*)(&tp[lskip_offset]))[6] =
831 ((uint64_t*)(&bp[lskip_offset]))[6];
832 ((uint64_t*)(&tp[lskip_offset]))[7] =
833 ((uint64_t*)(&bp[lskip_offset]))[7];
834 }
835 tp += tile_stride;
836 bp += buf_stride;
837 }
838 break;
839 default:
840 unaligned:
841 for (row = offsety;
842 row < tile_height && y < height;
843 row++, y++)
844 {
845 if (buffer_y + y >= buffer_abyss_y &&
846 buffer_y + y < abyss_y_total)
847 {
848 memcpy (tp + lskip_offset,
849 bp + lskip_offset,
850 pixels * px_size);
851 }
852 tp += tile_stride;
853 bp += buf_stride;
854 }
855 }
856
857 #undef CHECK_ALIGNMENT
858 #undef CHECK_ALIGNMENT_ALIGNOF
859 }
860
861 gegl_tile_unlock_no_void (tile);
862 gegl_tile_unref (tile);
863 bufx += (tile_width - offsetx);
864 }
865 bufy += (tile_height - offsety);
866 }
867
868 if (level == 0)
869 {
870 gegl_tile_handler_damage_rect (GEGL_TILE_HANDLER (buffer->tile_storage),
871 GEGL_RECTANGLE (buffer_x, buffer_y,
872 width, height));
873 }
874 }
875
876 static inline void
gegl_buffer_set_internal(GeglBuffer * buffer,const GeglRectangle * rect,gint level,const Babl * format,const void * src,gint rowstride)877 gegl_buffer_set_internal (GeglBuffer *buffer,
878 const GeglRectangle *rect,
879 gint level,
880 const Babl *format,
881 const void *src,
882 gint rowstride)
883 {
884 if (gegl_buffer_ext_flush)
885 {
886 gegl_buffer_ext_flush (buffer, rect);
887 }
888
889 gegl_buffer_iterate_write (buffer, rect, (void *) src, rowstride, format, level);
890
891 if (G_UNLIKELY (gegl_buffer_is_shared (buffer)))
892 {
893 gegl_buffer_flush (buffer);
894 }
895 }
896
897 static void inline
_gegl_buffer_set_with_flags(GeglBuffer * buffer,const GeglRectangle * rect,gint level,const Babl * format,const void * src,gint rowstride,GeglBufferSetFlag flags)898 _gegl_buffer_set_with_flags (GeglBuffer *buffer,
899 const GeglRectangle *rect,
900 gint level,
901 const Babl *format,
902 const void *src,
903 gint rowstride,
904 GeglBufferSetFlag flags)
905 {
906 switch (flags)
907 {
908 case GEGL_BUFFER_SET_FLAG_FAST:
909 gegl_buffer_set_internal (buffer, rect, level, format, src, rowstride);
910 break;
911 case GEGL_BUFFER_SET_FLAG_LOCK:
912 gegl_buffer_lock (buffer);
913 gegl_buffer_set_internal (buffer, rect, level, format, src, rowstride);
914 gegl_buffer_unlock (buffer);
915 break;
916 case GEGL_BUFFER_SET_FLAG_NOTIFY:
917 gegl_buffer_set_internal (buffer, rect, level, format, src, rowstride);
918 if (flags & GEGL_BUFFER_SET_FLAG_NOTIFY)
919 gegl_buffer_emit_changed_signal(buffer, rect);
920 break;
921 case GEGL_BUFFER_SET_FLAG_LOCK|GEGL_BUFFER_SET_FLAG_NOTIFY:
922 default:
923 gegl_buffer_lock (buffer);
924 gegl_buffer_set_internal (buffer, rect, level, format, src, rowstride);
925 gegl_buffer_unlock (buffer);
926 gegl_buffer_emit_changed_signal(buffer, rect);
927 break;
928 }
929 }
930
931 void
gegl_buffer_set_with_flags(GeglBuffer * buffer,const GeglRectangle * rect,gint level,const Babl * format,const void * src,gint rowstride,GeglBufferSetFlag flags)932 gegl_buffer_set_with_flags (GeglBuffer *buffer,
933 const GeglRectangle *rect,
934 gint level,
935 const Babl *format,
936 const void *src,
937 gint rowstride,
938 GeglBufferSetFlag flags)
939 {
940 g_return_if_fail (GEGL_IS_BUFFER (buffer));
941 if (format == NULL)
942 format = buffer->soft_format;
943 _gegl_buffer_set_with_flags (buffer, rect, level, format, src, rowstride, flags);
944 }
945
946 static void
gegl_buffer_iterate_read_simple(GeglBuffer * buffer,const GeglRectangle * roi,guchar * buf,gint buf_stride,const Babl * format,gint level)947 gegl_buffer_iterate_read_simple (GeglBuffer *buffer,
948 const GeglRectangle *roi,
949 guchar *buf,
950 gint buf_stride,
951 const Babl *format,
952 gint level)
953 {
954 gint tile_width = buffer->tile_storage->tile_width;
955 gint tile_height = buffer->tile_storage->tile_height;
956 gint px_size = babl_format_get_bytes_per_pixel (buffer->soft_format);
957 gint bpx_size = babl_format_get_bytes_per_pixel (format);
958 gint tile_stride = px_size * tile_width;
959 gint bufy = 0;
960
961 gint width = roi->width;
962 gint height = roi->height;
963 gint buffer_x = roi->x;
964 gint buffer_y = roi->y;
965
966 const Babl *fish;
967
968 if (G_LIKELY (format == buffer->soft_format))
969 fish = NULL;
970 else
971 fish = babl_fish ((gpointer) buffer->soft_format,
972 (gpointer) format);
973
974 while (bufy < height)
975 {
976 gint tiledy = buffer_y + bufy;
977 gint offsety = gegl_tile_offset (tiledy, tile_height);
978 gint bufx = 0;
979
980 while (bufx < width)
981 {
982 gint tiledx = buffer_x + bufx;
983 gint offsetx = gegl_tile_offset (tiledx, tile_width);
984 guchar *bp, *tile_base, *tp;
985 gint pixels, row, y;
986 GeglTile *tile;
987
988 bp = buf + (gsize) bufy * buf_stride + bufx * bpx_size;
989
990 if (G_LIKELY (width + offsetx - bufx < tile_width))
991 pixels = width - bufx;
992 else
993 pixels = tile_width - offsetx;
994
995 g_rec_mutex_lock (&buffer->tile_storage->mutex);
996 tile = gegl_tile_source_get_tile ((GeglTileSource *) (buffer),
997 gegl_tile_indice (tiledx, tile_width),
998 gegl_tile_indice (tiledy, tile_height),
999 level);
1000 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
1001
1002 if (!tile)
1003 {
1004 g_warning ("didn't get tile, trying to continue");
1005 bufx += (tile_width - offsetx);
1006 continue;
1007 }
1008
1009 gegl_tile_read_lock (tile);
1010
1011 tile_base = gegl_tile_get_data (tile);
1012 tp = ((guchar *) tile_base) + (offsety * tile_width + offsetx) * px_size;
1013
1014 y = bufy;
1015
1016 if (G_UNLIKELY (fish))
1017 {
1018 int rows = MIN(height - bufy, tile_height - offsety);
1019 if (rows == 1)
1020 babl_process (fish,
1021 tp,
1022 bp,
1023 pixels);
1024 else
1025 babl_process_rows (fish,
1026 tp,
1027 tile_stride,
1028 bp,
1029 buf_stride,
1030 pixels,
1031 rows);
1032
1033 }
1034 else
1035 {
1036 #ifdef __GNUC__
1037 #define CHECK_ALIGNMENT_ALIGNOF __alignof__
1038 #else
1039 #define CHECK_ALIGNMENT_ALIGNOF(type) \
1040 (G_STRUCT_OFFSET (struct alignof_helper, b))
1041 #endif
1042 #define CHECK_ALIGNMENT(type) \
1043 do \
1044 { \
1045 struct alignof_helper { char a; type b; }; \
1046 /* verify 'alignof (type)' is a power of 2 */ \
1047 G_STATIC_ASSERT (! (CHECK_ALIGNMENT_ALIGNOF (type) & \
1048 (CHECK_ALIGNMENT_ALIGNOF (type) - 1)));\
1049 if (((uintptr_t) tp | \
1050 (uintptr_t) bp | \
1051 tile_stride | \
1052 buf_stride) & \
1053 (CHECK_ALIGNMENT_ALIGNOF (type) - 1)) \
1054 { \
1055 goto unaligned; \
1056 } \
1057 } \
1058 while (FALSE)
1059
1060 switch (pixels * px_size)
1061 {
1062 case 1:
1063 CHECK_ALIGNMENT (guchar);
1064 for (row = offsety; row < tile_height && y < height;
1065 row++, y++)
1066 {
1067 bp[0] = tp[0];
1068 tp += tile_stride;
1069 bp += buf_stride;
1070 }
1071 break;
1072 case 2:
1073 CHECK_ALIGNMENT (uint16_t);
1074 for (row = offsety; row < tile_height && y < height;
1075 row++, y++)
1076 {
1077 ((uint16_t*)bp)[0] = ((uint16_t*)tp)[0];
1078 tp += tile_stride;
1079 bp += buf_stride;
1080 }
1081 break;
1082 case 3:
1083 CHECK_ALIGNMENT (guchar);
1084 for (row = offsety; row < tile_height && y < height;
1085 row++, y++)
1086 {
1087 bp[0] = tp[0];
1088 bp[1] = tp[1];
1089 bp[2] = tp[2];
1090 tp += tile_stride;
1091 bp += buf_stride;
1092 }
1093 break;
1094 case 4:
1095 CHECK_ALIGNMENT (uint32_t);
1096 for (row = offsety; row < tile_height && y < height;
1097 row++, y++)
1098 {
1099 ((uint32_t*)bp)[0] = ((uint32_t*)tp)[0];
1100 tp += tile_stride;
1101 bp += buf_stride;
1102 }
1103 break;
1104 case 6:
1105 CHECK_ALIGNMENT (uint16_t);
1106 for (row = offsety; row < tile_height && y < height;
1107 row++, y++)
1108 {
1109 ((uint16_t*)bp)[0] = ((uint16_t*)tp)[0];
1110 ((uint16_t*)bp)[1] = ((uint16_t*)tp)[1];
1111 ((uint16_t*)bp)[2] = ((uint16_t*)tp)[2];
1112 tp += tile_stride;
1113 bp += buf_stride;
1114 }
1115 break;
1116 case 8:
1117 CHECK_ALIGNMENT (uint64_t);
1118 for (row = offsety; row < tile_height && y < height;
1119 row++, y++)
1120 {
1121 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1122 tp += tile_stride;
1123 bp += buf_stride;
1124 }
1125 break;
1126 case 12:
1127 CHECK_ALIGNMENT (uint32_t);
1128 for (row = offsety; row < tile_height && y < height;
1129 row++, y++)
1130 {
1131 ((uint32_t*)bp)[0] = ((uint32_t*)tp)[0];
1132 ((uint32_t*)bp)[1] = ((uint32_t*)tp)[1];
1133 ((uint32_t*)bp)[2] = ((uint32_t*)tp)[2];
1134 tp += tile_stride;
1135 bp += buf_stride;
1136 }
1137 break;
1138 case 16:
1139 CHECK_ALIGNMENT (uint64_t);
1140 for (row = offsety; row < tile_height && y < height;
1141 row++, y++)
1142 {
1143 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1144 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1145 tp += tile_stride;
1146 bp += buf_stride;
1147 }
1148 break;
1149 case 24:
1150 CHECK_ALIGNMENT (uint64_t);
1151 for (row = offsety; row < tile_height && y < height;
1152 row++, y++)
1153 {
1154 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1155 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1156 ((uint64_t*)bp)[2] = ((uint64_t*)tp)[2];
1157 tp += tile_stride;
1158 bp += buf_stride;
1159 }
1160 break;
1161 case 32:
1162 CHECK_ALIGNMENT (uint64_t);
1163 for (row = offsety; row < tile_height && y < height;
1164 row++, y++)
1165 {
1166 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1167 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1168 ((uint64_t*)bp)[2] = ((uint64_t*)tp)[2];
1169 ((uint64_t*)bp)[3] = ((uint64_t*)tp)[3];
1170 tp += tile_stride;
1171 bp += buf_stride;
1172 }
1173 break;
1174 case 40:
1175 CHECK_ALIGNMENT (uint64_t);
1176 for (row = offsety; row < tile_height && y < height;
1177 row++, y++)
1178 {
1179 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1180 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1181 ((uint64_t*)bp)[2] = ((uint64_t*)tp)[2];
1182 ((uint64_t*)bp)[3] = ((uint64_t*)tp)[3];
1183 ((uint64_t*)bp)[4] = ((uint64_t*)tp)[4];
1184 tp += tile_stride;
1185 bp += buf_stride;
1186 }
1187 break;
1188 case 48:
1189 CHECK_ALIGNMENT (uint64_t);
1190 for (row = offsety; row < tile_height && y < height;
1191 row++, y++)
1192 {
1193 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1194 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1195 ((uint64_t*)bp)[2] = ((uint64_t*)tp)[2];
1196 ((uint64_t*)bp)[3] = ((uint64_t*)tp)[3];
1197 ((uint64_t*)bp)[4] = ((uint64_t*)tp)[4];
1198 ((uint64_t*)bp)[5] = ((uint64_t*)tp)[5];
1199 tp += tile_stride;
1200 bp += buf_stride;
1201 }
1202 break;
1203 case 56:
1204 CHECK_ALIGNMENT (uint64_t);
1205 for (row = offsety; row < tile_height && y < height;
1206 row++, y++)
1207 {
1208 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1209 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1210 ((uint64_t*)bp)[2] = ((uint64_t*)tp)[2];
1211 ((uint64_t*)bp)[3] = ((uint64_t*)tp)[3];
1212 ((uint64_t*)bp)[4] = ((uint64_t*)tp)[4];
1213 ((uint64_t*)bp)[5] = ((uint64_t*)tp)[5];
1214 ((uint64_t*)bp)[6] = ((uint64_t*)tp)[6];
1215 tp += tile_stride;
1216 bp += buf_stride;
1217 }
1218 break;
1219 case 64:
1220 CHECK_ALIGNMENT (uint64_t);
1221 for (row = offsety; row < tile_height && y < height;
1222 row++, y++)
1223 {
1224 ((uint64_t*)bp)[0] = ((uint64_t*)tp)[0];
1225 ((uint64_t*)bp)[1] = ((uint64_t*)tp)[1];
1226 ((uint64_t*)bp)[2] = ((uint64_t*)tp)[2];
1227 ((uint64_t*)bp)[3] = ((uint64_t*)tp)[3];
1228 ((uint64_t*)bp)[4] = ((uint64_t*)tp)[4];
1229 ((uint64_t*)bp)[5] = ((uint64_t*)tp)[5];
1230 ((uint64_t*)bp)[6] = ((uint64_t*)tp)[6];
1231 ((uint64_t*)bp)[7] = ((uint64_t*)tp)[7];
1232 tp += tile_stride;
1233 bp += buf_stride;
1234 }
1235 break;
1236
1237 default:
1238 unaligned:
1239 for (row = offsety;
1240 row < tile_height && y < height;
1241 row++, y++)
1242 {
1243 memcpy (bp, tp, pixels * px_size);
1244 tp += tile_stride;
1245 bp += buf_stride;
1246 }
1247 }
1248
1249 #undef CHECK_ALIGNMENT
1250 #undef CHECK_ALIGNMENT_ALIGNOF
1251 }
1252
1253 gegl_tile_read_unlock (tile);
1254 gegl_tile_unref (tile);
1255 bufx += (tile_width - offsetx);
1256 }
1257 bufy += (tile_height - offsety);
1258 }
1259
1260 }
1261
1262 static void
fill_abyss_none(guchar * buf,gint width,gint height,gint buf_stride,gint pixel_size)1263 fill_abyss_none (guchar *buf, gint width, gint height, gint buf_stride, gint pixel_size)
1264 {
1265 const int byte_width = width * pixel_size;
1266
1267 if (buf_stride == byte_width)
1268 {
1269 memset (buf, 0, byte_width * height);
1270 }
1271 else
1272 {
1273 while (height--)
1274 {
1275 memset (buf, 0, byte_width);
1276 buf += buf_stride;
1277 }
1278 }
1279 }
1280
1281 static void
fill_abyss_color(guchar * buf,gint width,gint height,gint buf_stride,guchar * pixel,gint pixel_size)1282 fill_abyss_color (guchar *buf, gint width, gint height, gint buf_stride, guchar *pixel, gint pixel_size)
1283 {
1284 if (buf_stride == width * pixel_size)
1285 {
1286 gegl_memset_pattern (buf, pixel, pixel_size, width * height);
1287 }
1288 else
1289 {
1290 while (height--)
1291 {
1292 gegl_memset_pattern (buf, pixel, pixel_size, width);
1293 buf += buf_stride;
1294 }
1295 }
1296 }
1297
1298 static void
gegl_buffer_iterate_read_abyss_color(GeglBuffer * buffer,const GeglRectangle * roi,const GeglRectangle * abyss,guchar * buf,gint buf_stride,const Babl * format,gint level,guchar * color,GeglAbyssPolicy repeat_mode)1299 gegl_buffer_iterate_read_abyss_color (GeglBuffer *buffer,
1300 const GeglRectangle *roi,
1301 const GeglRectangle *abyss,
1302 guchar *buf,
1303 gint buf_stride,
1304 const Babl *format,
1305 gint level,
1306 guchar *color,
1307 GeglAbyssPolicy repeat_mode)
1308 {
1309 GeglRectangle current_roi = *roi;
1310 gint bpp = babl_format_get_bytes_per_pixel (format);
1311
1312 if (current_roi.y < abyss->y)
1313 {
1314 /* Abyss above image */
1315 gint height = abyss->y - current_roi.y;
1316 if (current_roi.height < height)
1317 height = current_roi.height;
1318 if (color)
1319 fill_abyss_color (buf, current_roi.width, height, buf_stride, color, bpp);
1320 else
1321 fill_abyss_none (buf, current_roi.width, height, buf_stride, bpp);
1322 buf += buf_stride * height;
1323 current_roi.y += height;
1324 current_roi.height -= height;
1325 }
1326
1327 if (current_roi.height && (current_roi.y < abyss->y + abyss->height))
1328 {
1329 GeglRectangle inner_roi = current_roi;
1330 guchar *inner_buf = buf;
1331
1332 if (inner_roi.height + inner_roi.y > abyss->height + abyss->y)
1333 {
1334 /* Clamp inner_roi to the in abyss height */
1335 inner_roi.height -= (inner_roi.height + inner_roi.y) - (abyss->height + abyss->y);
1336 }
1337
1338 if (inner_roi.x < abyss->x)
1339 {
1340 /* Abyss left of image */
1341 gint width = abyss->x - inner_roi.x;
1342 if (width > inner_roi.width)
1343 width = inner_roi.width;
1344
1345 if (color)
1346 fill_abyss_color (inner_buf, width, inner_roi.height, buf_stride, color, bpp);
1347 else
1348 fill_abyss_none (inner_buf, width, inner_roi.height, buf_stride, bpp);
1349 inner_buf += width * bpp;
1350 inner_roi.x += width;
1351 inner_roi.width -= width;
1352 }
1353
1354 if (inner_roi.width && (inner_roi.x < abyss->x + abyss->width))
1355 {
1356 gint full_width = inner_roi.width;
1357
1358 if (inner_roi.width + inner_roi.x > abyss->width + abyss->x)
1359 {
1360 /* Clamp inner_roi to the in abyss width */
1361 inner_roi.width -= (inner_roi.width + inner_roi.x) - (abyss->width + abyss->x);
1362 }
1363
1364 if (level)
1365 gegl_buffer_iterate_read_fringed (buffer,
1366 &inner_roi,
1367 abyss,
1368 inner_buf,
1369 buf_stride,
1370 format,
1371 level,
1372 repeat_mode);
1373 else
1374 gegl_buffer_iterate_read_simple (buffer,
1375 &inner_roi,
1376 inner_buf,
1377 buf_stride,
1378 format,
1379 level);
1380
1381 inner_buf += inner_roi.width * bpp;
1382 inner_roi.width = full_width - inner_roi.width;
1383 }
1384
1385 if (inner_roi.width)
1386 {
1387 /* Abyss right of image */
1388 if (color)
1389 fill_abyss_color (inner_buf, inner_roi.width, inner_roi.height, buf_stride, color, bpp);
1390 else
1391 fill_abyss_none (inner_buf, inner_roi.width, inner_roi.height, buf_stride, bpp);
1392 }
1393
1394 buf += inner_roi.height * buf_stride;
1395 /* current_roi.y += inner_roi.height; */
1396 current_roi.height -= inner_roi.height;
1397 }
1398
1399 if (current_roi.height)
1400 {
1401 /* Abyss below image */
1402 if (color)
1403 fill_abyss_color (buf, current_roi.width, current_roi.height, buf_stride, color, bpp);
1404 else
1405 fill_abyss_none (buf, current_roi.width, current_roi.height, buf_stride, bpp);
1406 }
1407 }
1408
1409 static void
gegl_buffer_iterate_read_abyss_clamp(GeglBuffer * buffer,const GeglRectangle * roi,const GeglRectangle * abyss,guchar * buf,gint buf_stride,const Babl * format,gint level)1410 gegl_buffer_iterate_read_abyss_clamp (GeglBuffer *buffer,
1411 const GeglRectangle *roi,
1412 const GeglRectangle *abyss,
1413 guchar *buf,
1414 gint buf_stride,
1415 const Babl *format,
1416 gint level)
1417 {
1418 GeglRectangle read_output_rect;
1419 GeglRectangle read_input_rect;
1420
1421 gint bpp = babl_format_get_bytes_per_pixel (format);
1422 gint x_read_offset = 0;
1423 gint y_read_offset = 0;
1424 gint buf_offset_cols;
1425 gint buf_offset_rows;
1426 gint top_rows, left_cols, right_cols, bottom_rows;
1427 guchar *read_buf;
1428
1429 if (roi->x >= abyss->x + abyss->width) /* Right of */
1430 x_read_offset = roi->x - (abyss->x + abyss->width) + 1;
1431 else if (roi->x + roi->width <= abyss->x) /* Left of */
1432 x_read_offset = (roi->x + roi->width) - abyss->x - 1;
1433
1434 if (roi->y >= abyss->y + abyss->height) /* Above */
1435 y_read_offset = roi->y - (abyss->y + abyss->height) + 1;
1436 else if (roi->y + roi->height <= abyss->y) /* Below of */
1437 y_read_offset = (roi->y + roi->height) - abyss->y - 1;
1438
1439 /* Intersect our shifted abyss with the roi */
1440 gegl_rectangle_intersect (&read_output_rect,
1441 roi,
1442 GEGL_RECTANGLE (abyss->x + x_read_offset,
1443 abyss->y + y_read_offset,
1444 abyss->width,
1445 abyss->height));
1446
1447 /* Offset into *buf based on the intersected rect's x & y */
1448 buf_offset_cols = read_output_rect.x - roi->x;
1449 buf_offset_rows = read_output_rect.y - roi->y;
1450 read_buf = buf + (buf_offset_cols * bpp + buf_offset_rows * buf_stride);
1451
1452 /* Convert the read output to a coresponding input */
1453 read_input_rect.x = read_output_rect.x - x_read_offset;
1454 read_input_rect.y = read_output_rect.y - y_read_offset;
1455 read_input_rect.width = read_output_rect.width;
1456 read_input_rect.height = read_output_rect.height;
1457 #if 1
1458 if (level)
1459 gegl_buffer_iterate_read_fringed (buffer,
1460 &read_input_rect,
1461 abyss,
1462 read_buf,
1463 buf_stride,
1464 format,
1465 level,
1466 GEGL_ABYSS_CLAMP);
1467 else
1468 #endif
1469 gegl_buffer_iterate_read_simple (buffer,
1470 &read_input_rect,
1471 read_buf,
1472 buf_stride,
1473 format,
1474 level);
1475
1476 /* All calculations are done relative to read_output_rect because it is guranteed
1477 * to be inside of the roi rect and none of these calculations can return a value
1478 * less than 0.
1479 */
1480 top_rows = read_output_rect.y - roi->y;
1481 left_cols = read_output_rect.x - roi->x;
1482 right_cols = (roi->x + roi->width) - (read_output_rect.x + read_output_rect.width);
1483 bottom_rows = (roi->y + roi->height) - (read_output_rect.y + read_output_rect.height);
1484
1485 if (top_rows)
1486 {
1487 guchar *fill_buf = buf;
1488 /* Top left pixel */
1489 if (left_cols)
1490 {
1491 guchar *src_pixel = read_buf;
1492 fill_abyss_color (fill_buf, left_cols, top_rows, buf_stride, src_pixel, bpp);
1493 fill_buf += left_cols * bpp;
1494 }
1495
1496 /* Top rows */
1497 {
1498 guchar *src_pixel = read_buf;
1499 guchar *row_fill_buf = fill_buf;
1500 gint byte_width = read_output_rect.width * bpp;
1501 gint i;
1502 for (i = 0; i < top_rows; ++i)
1503 {
1504 memcpy (row_fill_buf, src_pixel, byte_width);
1505 row_fill_buf += buf_stride;
1506 }
1507 }
1508
1509 fill_buf += (read_input_rect.width) * bpp;
1510 /* Top right pixel */
1511 if (right_cols)
1512 {
1513 guchar *src_pixel = read_buf + (read_input_rect.width - 1) * bpp;
1514 fill_abyss_color (fill_buf, right_cols, top_rows, buf_stride, src_pixel, bpp);
1515 }
1516 }
1517
1518 /* Left */
1519 if (left_cols)
1520 {
1521 guchar *row_fill_buf = buf + (top_rows * buf_stride);
1522 guchar *src_pixel = read_buf;
1523 gint i;
1524
1525 for (i = 0; i < read_output_rect.height; ++i)
1526 {
1527 gegl_memset_pattern (row_fill_buf, src_pixel, bpp, left_cols);
1528 row_fill_buf += buf_stride;
1529 src_pixel += buf_stride;
1530 }
1531 }
1532
1533 /* Right */
1534 if (right_cols)
1535 {
1536 guchar *row_fill_buf = buf + (read_input_rect.width + left_cols) * bpp
1537 + top_rows * buf_stride;
1538 guchar *src_pixel = read_buf + (read_input_rect.width - 1) * bpp;
1539 gint i;
1540
1541 for (i = 0; i < read_output_rect.height; ++i)
1542 {
1543 gegl_memset_pattern (row_fill_buf, src_pixel, bpp, right_cols);
1544 row_fill_buf += buf_stride;
1545 src_pixel += buf_stride;
1546 }
1547 }
1548
1549 if (bottom_rows)
1550 {
1551 guchar *fill_buf = buf + (read_input_rect.height + top_rows) * buf_stride;
1552 /* Bottom left */
1553 if (left_cols)
1554 {
1555 guchar *src_pixel = read_buf + (read_input_rect.height - 1) * buf_stride;
1556 fill_abyss_color (fill_buf, left_cols, bottom_rows, buf_stride, src_pixel, bpp);
1557 fill_buf += left_cols * bpp;
1558 }
1559
1560 /* Bottom rows */
1561 {
1562 guchar *src_pixel = read_buf + (read_input_rect.height - 1) * buf_stride;
1563 guchar *row_fill_buf = fill_buf;
1564 gint byte_width = read_output_rect.width * bpp;
1565 gint i;
1566 for (i = 0; i < bottom_rows; ++i)
1567 {
1568 memcpy (row_fill_buf, src_pixel, byte_width);
1569 row_fill_buf += buf_stride;
1570 }
1571 }
1572
1573 fill_buf += read_input_rect.width * bpp;
1574 /* Bottom right */
1575 if (right_cols)
1576 {
1577 guchar *src_pixel = read_buf + (read_input_rect.width - 1) * bpp + (read_input_rect.height - 1) * buf_stride;
1578 fill_abyss_color (fill_buf, right_cols, bottom_rows, buf_stride, src_pixel, bpp);
1579 }
1580 }
1581 }
1582
1583 static void
gegl_buffer_iterate_read_abyss_loop(GeglBuffer * buffer,const GeglRectangle * roi,const GeglRectangle * abyss,guchar * buf,gint buf_stride,const Babl * format,gint level)1584 gegl_buffer_iterate_read_abyss_loop (GeglBuffer *buffer,
1585 const GeglRectangle *roi,
1586 const GeglRectangle *abyss,
1587 guchar *buf,
1588 gint buf_stride,
1589 const Babl *format,
1590 gint level)
1591 {
1592 GeglRectangle current_roi;
1593 gint bpp = babl_format_get_bytes_per_pixel (format);
1594 gint origin_x;
1595
1596 /* Loop abyss works like iterating over a grid of tiles the size of the abyss */
1597 gint loop_chunk_ix = gegl_tile_indice (roi->x - abyss->x, abyss->width);
1598 gint loop_chunk_iy = gegl_tile_indice (roi->y - abyss->y, abyss->height);
1599
1600 current_roi.x = loop_chunk_ix * abyss->width + abyss->x;
1601 current_roi.y = loop_chunk_iy * abyss->height + abyss->y;
1602
1603 current_roi.width = abyss->width;
1604 current_roi.height = abyss->height;
1605
1606 origin_x = current_roi.x;
1607
1608 while (current_roi.y < roi->y + roi->height)
1609 {
1610 guchar *inner_buf = buf;
1611 gint row_height = 0;
1612
1613 while (current_roi.x < roi->x + roi->width)
1614 {
1615 GeglRectangle simple_roi;
1616 gegl_rectangle_intersect (&simple_roi, ¤t_roi, roi);
1617
1618 gegl_buffer_iterate_read_simple (buffer,
1619 GEGL_RECTANGLE (abyss->x + (simple_roi.x - current_roi.x),
1620 abyss->y + (simple_roi.y - current_roi.y),
1621 simple_roi.width,
1622 simple_roi.height),
1623 inner_buf,
1624 buf_stride,
1625 format,
1626 level);
1627
1628 row_height = simple_roi.height;
1629 inner_buf += simple_roi.width * bpp;
1630
1631 current_roi.x += abyss->width;
1632 }
1633
1634 buf += buf_stride * row_height;
1635
1636 current_roi.x = origin_x;
1637 current_roi.y += abyss->height;
1638 }
1639 }
1640
1641 static gpointer
gegl_buffer_read_at_level(GeglBuffer * buffer,const GeglRectangle * roi,guchar * buf,gint rowstride,const Babl * format,gint level,GeglAbyssPolicy repeat_mode)1642 gegl_buffer_read_at_level (GeglBuffer *buffer,
1643 const GeglRectangle *roi,
1644 guchar *buf,
1645 gint rowstride,
1646 const Babl *format,
1647 gint level,
1648 GeglAbyssPolicy repeat_mode)
1649 {
1650 gint bpp = babl_format_get_bytes_per_pixel (format);
1651
1652 if (level == 0)
1653 {
1654 if (!buf)
1655 {
1656 gpointer scratch = gegl_scratch_alloc (bpp * roi->width * roi->height);
1657
1658 gegl_buffer_iterate_read_dispatch (buffer, roi, scratch, roi->width * bpp, format, 0, repeat_mode);
1659
1660 return scratch;
1661 }
1662 else
1663 {
1664 gegl_buffer_iterate_read_dispatch (buffer, roi, buf, rowstride, format, 0, repeat_mode);
1665
1666 return NULL;
1667 }
1668 }
1669 else
1670 {
1671 gpointer scratch;
1672 GeglRectangle next_roi;
1673 next_roi.x = roi->x * 2;
1674 next_roi.y = roi->y * 2;
1675 next_roi.width = roi->width * 2;
1676 next_roi.height = roi->height * 2;
1677
1678 /* If the next block is too big split it in half */
1679 if (next_roi.width * next_roi.height > 256 * 256)
1680 {
1681 GeglRectangle next_roi_a = next_roi;
1682 GeglRectangle next_roi_b = next_roi;
1683 gint scratch_stride = next_roi.width * bpp;
1684 gpointer scratch_a;
1685 gpointer scratch_b;
1686 scratch = gegl_scratch_alloc (bpp * next_roi.width * next_roi.height);
1687
1688 if (next_roi.width > next_roi.height)
1689 {
1690 next_roi_a.width = roi->width;
1691 next_roi_b.width = roi->width;
1692 next_roi_b.x += next_roi_a.width;
1693
1694 scratch_a = scratch;
1695 scratch_b = (guchar *)scratch + next_roi_a.width * bpp;
1696 }
1697 else
1698 {
1699 next_roi_a.height = roi->height;
1700 next_roi_b.height = roi->height;
1701 next_roi_b.y += next_roi_a.height;
1702
1703 scratch_a = scratch;
1704 scratch_b = (guchar *)scratch + next_roi_a.height * scratch_stride;
1705 }
1706
1707 gegl_buffer_read_at_level (buffer, &next_roi_a, scratch_a, scratch_stride, format, level - 1, repeat_mode);
1708 gegl_buffer_read_at_level (buffer, &next_roi_b, scratch_b, scratch_stride, format, level - 1, repeat_mode);
1709
1710 }
1711 else
1712 {
1713 scratch = gegl_buffer_read_at_level (buffer, &next_roi, NULL, 0, format, level - 1, repeat_mode);
1714 }
1715
1716 if (buf)
1717 {
1718 gegl_downscale_2x2 (format,
1719 next_roi.width,
1720 next_roi.height,
1721 scratch,
1722 next_roi.width * bpp,
1723 buf,
1724 rowstride);
1725 gegl_scratch_free (scratch);
1726 return NULL;
1727 }
1728 else
1729 {
1730 gegl_downscale_2x2 (format,
1731 next_roi.width,
1732 next_roi.height,
1733 scratch,
1734 next_roi.width * bpp,
1735 scratch,
1736 roi->width * bpp);
1737 return scratch;
1738 }
1739 }
1740 }
1741
1742 static void
gegl_buffer_iterate_read_fringed(GeglBuffer * buffer,const GeglRectangle * roi,const GeglRectangle * abyss,guchar * buf,gint buf_stride,const Babl * format,gint level,GeglAbyssPolicy repeat_mode)1743 gegl_buffer_iterate_read_fringed (GeglBuffer *buffer,
1744 const GeglRectangle *roi,
1745 const GeglRectangle *abyss,
1746 guchar *buf,
1747 gint buf_stride,
1748 const Babl *format,
1749 gint level,
1750 GeglAbyssPolicy repeat_mode)
1751 {
1752 gint x = roi->x;
1753 gint y = roi->y;
1754 gint width = roi->width;
1755 gint height = roi->height;
1756 guchar *inner_buf = buf;
1757
1758 gint bpp = babl_format_get_bytes_per_pixel (format);
1759
1760 if (x <= abyss->x)
1761 {
1762 GeglRectangle fringe_roi = {x, y, 1, height};
1763 guchar *fringe_buf = inner_buf;
1764
1765 gegl_buffer_read_at_level (buffer, &fringe_roi, fringe_buf, buf_stride, format, level, repeat_mode);
1766 inner_buf += bpp;
1767 x += 1;
1768 width -= 1;
1769
1770 if (!width)
1771 return;
1772 }
1773
1774 if (y <= abyss->y)
1775 {
1776 GeglRectangle fringe_roi = {x, y, width, 1};
1777 guchar *fringe_buf = inner_buf;
1778
1779 gegl_buffer_read_at_level (buffer, &fringe_roi, fringe_buf, buf_stride, format, level, repeat_mode);
1780 inner_buf += buf_stride;
1781 y += 1;
1782 height -= 1;
1783
1784 if (!height)
1785 return;
1786 }
1787
1788 if (y + height >= abyss->y + abyss->height)
1789 {
1790 GeglRectangle fringe_roi = {x, y + height - 1, width, 1};
1791 guchar *fringe_buf = inner_buf + (height - 1) * buf_stride;
1792
1793 gegl_buffer_read_at_level (buffer, &fringe_roi, fringe_buf, buf_stride, format, level, repeat_mode);
1794 height -= 1;
1795
1796 if (!height)
1797 return;
1798 }
1799
1800 if (x + width >= abyss->x + abyss->width)
1801 {
1802 GeglRectangle fringe_roi = {x + width - 1, y, 1, height};
1803 guchar *fringe_buf = inner_buf + (width - 1) * bpp;
1804
1805 gegl_buffer_read_at_level (buffer, &fringe_roi, fringe_buf, buf_stride, format, level, repeat_mode);
1806 width -= 1;
1807
1808 if (!width)
1809 return;
1810 }
1811
1812 gegl_buffer_iterate_read_simple (buffer,
1813 GEGL_RECTANGLE (x, y, width, height),
1814 inner_buf,
1815 buf_stride,
1816 format,
1817 level);
1818 }
1819
1820 static void
gegl_buffer_iterate_read_dispatch(GeglBuffer * buffer,const GeglRectangle * roi,guchar * buf,gint rowstride,const Babl * format,gint level,GeglAbyssPolicy repeat_mode)1821 gegl_buffer_iterate_read_dispatch (GeglBuffer *buffer,
1822 const GeglRectangle *roi,
1823 guchar *buf,
1824 gint rowstride,
1825 const Babl *format,
1826 gint level,
1827 GeglAbyssPolicy repeat_mode)
1828 {
1829 GeglRectangle abyss = buffer->abyss;
1830 GeglRectangle abyss_factored = abyss;
1831 GeglRectangle roi_factored = *roi;
1832
1833 if (level)
1834 {
1835 const gint factor = 1 << level;
1836 const gint x1 = buffer->shift_x + abyss.x;
1837 const gint y1 = buffer->shift_y + abyss.y;
1838 const gint x2 = buffer->shift_x + abyss.x + abyss.width;
1839 const gint y2 = buffer->shift_y + abyss.y + abyss.height;
1840
1841 abyss_factored.x = (x1 + (x1 < 0 ? 1 - factor : 0)) / factor;
1842 abyss_factored.y = (y1 + (y1 < 0 ? 1 - factor : 0)) / factor;
1843 abyss_factored.width = (x2 + (x2 < 0 ? 0 : factor - 1)) / factor - abyss_factored.x;
1844 abyss_factored.height = (y2 + (y2 < 0 ? 0 : factor - 1)) / factor - abyss_factored.y;
1845
1846 roi_factored.x = (buffer->shift_x + roi_factored.x) / factor;
1847 roi_factored.y = (buffer->shift_y + roi_factored.y) / factor;
1848 roi_factored.width /= factor;
1849 roi_factored.height /= factor;
1850 }
1851 else
1852 {
1853 roi_factored.x += buffer->shift_x;
1854 roi_factored.y += buffer->shift_y;
1855 abyss_factored.x += buffer->shift_x;
1856 abyss_factored.y += buffer->shift_y;
1857 }
1858
1859 if (rowstride == GEGL_AUTO_ROWSTRIDE)
1860 rowstride = roi_factored.width * babl_format_get_bytes_per_pixel (format);
1861
1862 if (gegl_rectangle_contains (&abyss, roi))
1863 {
1864 gegl_buffer_iterate_read_simple (buffer, &roi_factored, buf, rowstride, format, level);
1865 }
1866 else if (repeat_mode == GEGL_ABYSS_NONE)
1867 {
1868 gegl_buffer_iterate_read_abyss_color (buffer, &roi_factored, &abyss_factored,
1869 buf, rowstride, format, level, NULL,
1870 GEGL_ABYSS_NONE);
1871 }
1872 else if (repeat_mode == GEGL_ABYSS_WHITE)
1873 {
1874 guchar color[128];
1875 gfloat in_color[] = {1.0f, 1.0f, 1.0f, 1.0f};
1876
1877 babl_process (babl_fish (gegl_babl_rgba_linear_float (), format),
1878 in_color, color, 1);
1879
1880 gegl_buffer_iterate_read_abyss_color (buffer, &roi_factored, &abyss_factored,
1881 buf, rowstride, format, level, color,
1882 GEGL_ABYSS_WHITE);
1883 }
1884 else if (repeat_mode == GEGL_ABYSS_BLACK)
1885 {
1886 guchar color[128];
1887 gfloat in_color[] = {0.0f, 0.0f, 0.0f, 1.0f};
1888
1889 babl_process (babl_fish (gegl_babl_rgba_linear_float (), format),
1890 in_color, color, 1);
1891
1892 gegl_buffer_iterate_read_abyss_color (buffer, &roi_factored, &abyss_factored,
1893 buf, rowstride, format, level, color,
1894 GEGL_ABYSS_BLACK);
1895 }
1896 else if (repeat_mode == GEGL_ABYSS_CLAMP)
1897 {
1898 if (abyss_factored.width == 0 || abyss_factored.height == 0)
1899 gegl_buffer_iterate_read_abyss_color (buffer, &roi_factored, &abyss_factored,
1900 buf, rowstride, format, level, NULL,
1901 GEGL_ABYSS_NONE);
1902 else
1903 gegl_buffer_iterate_read_abyss_clamp (buffer, &roi_factored, &abyss_factored,
1904 buf, rowstride, format, level);
1905 }
1906 else
1907 {
1908 if (abyss_factored.width == 0 || abyss_factored.height == 0)
1909 gegl_buffer_iterate_read_abyss_color (buffer, &roi_factored, &abyss_factored,
1910 buf, rowstride, format, level, NULL,
1911 GEGL_ABYSS_NONE);
1912 else
1913 gegl_buffer_iterate_read_abyss_loop (buffer, &roi_factored, &abyss_factored,
1914 buf, rowstride, format, level);
1915 }
1916 }
1917
1918 void
gegl_buffer_set_unlocked(GeglBuffer * buffer,const GeglRectangle * rect,gint level,const Babl * format,const void * src,gint rowstride)1919 gegl_buffer_set_unlocked (GeglBuffer *buffer,
1920 const GeglRectangle *rect,
1921 gint level,
1922 const Babl *format,
1923 const void *src,
1924 gint rowstride)
1925 {
1926 _gegl_buffer_set_with_flags (buffer, rect, level, format, src, rowstride,
1927 GEGL_BUFFER_SET_FLAG_NOTIFY);
1928 }
1929
1930 void
gegl_buffer_set_unlocked_no_notify(GeglBuffer * buffer,const GeglRectangle * rect,gint level,const Babl * format,const void * src,gint rowstride)1931 gegl_buffer_set_unlocked_no_notify (GeglBuffer *buffer,
1932 const GeglRectangle *rect,
1933 gint level,
1934 const Babl *format,
1935 const void *src,
1936 gint rowstride)
1937 {
1938 _gegl_buffer_set_with_flags (buffer, rect, level, format, src, rowstride,
1939 GEGL_BUFFER_SET_FLAG_FAST);
1940 }
1941
1942
1943 void
gegl_buffer_set(GeglBuffer * buffer,const GeglRectangle * rect,gint level,const Babl * format,const void * src,gint rowstride)1944 gegl_buffer_set (GeglBuffer *buffer,
1945 const GeglRectangle *rect,
1946 gint level,
1947 const Babl *format,
1948 const void *src,
1949 gint rowstride)
1950 {
1951 g_return_if_fail (GEGL_IS_BUFFER (buffer));
1952
1953 if (G_UNLIKELY (gegl_rectangle_is_empty (rect ? rect : &buffer->extent)))
1954 return;
1955
1956 g_return_if_fail (src != NULL);
1957
1958 if (G_LIKELY (format == NULL))
1959 format = buffer->soft_format;
1960
1961 if (G_UNLIKELY (rect && rect->width == 1))
1962 {
1963 if (level == 0 && rect->height == 1)
1964 {
1965 _gegl_buffer_set_pixel (buffer, rect->x, rect->y,
1966 format, src,
1967 GEGL_BUFFER_SET_FLAG_LOCK|
1968 GEGL_BUFFER_SET_FLAG_NOTIFY);
1969 return;
1970 }
1971 else if (buffer->soft_format != format &&
1972 rowstride == babl_format_get_bytes_per_pixel (format))
1973 {
1974 int bpp = babl_format_get_bytes_per_pixel (buffer->soft_format);
1975 uint8_t tmp[rect->height * bpp];
1976 babl_process (babl_fish (format, buffer->soft_format),
1977 src, &tmp[0], rect->height);
1978 _gegl_buffer_set_with_flags (buffer, rect, level, buffer->soft_format, tmp, bpp,
1979 GEGL_BUFFER_SET_FLAG_LOCK|
1980 GEGL_BUFFER_SET_FLAG_NOTIFY);
1981 return;
1982 }
1983 }
1984
1985 _gegl_buffer_set_with_flags (buffer, rect, level, format, src, rowstride,
1986 GEGL_BUFFER_SET_FLAG_LOCK|
1987 GEGL_BUFFER_SET_FLAG_NOTIFY);
1988 }
1989
1990 /* Expand roi by scale so it uncludes all pixels needed
1991 * to satisfy a gegl_buffer_get() call at level 0.
1992 */
1993 GeglRectangle
_gegl_get_required_for_scale(const GeglRectangle * roi,gdouble scale)1994 _gegl_get_required_for_scale (const GeglRectangle *roi,
1995 gdouble scale)
1996 {
1997 if (GEGL_FLOAT_EQUAL (scale, 1.0))
1998 return *roi;
1999 else
2000 {
2001 gint x1 = int_floorf (roi->x / scale + GEGL_SCALE_EPSILON);
2002 gint x2 = int_ceilf ((roi->x + roi->width) / scale - GEGL_SCALE_EPSILON);
2003 gint y1 = int_floorf (roi->y / scale + GEGL_SCALE_EPSILON);
2004 gint y2 = int_ceilf ((roi->y + roi->height) / scale - GEGL_SCALE_EPSILON);
2005
2006 gint pad = (1.0 / scale > 1.0) ? int_ceilf (1.0 / scale) : 1;
2007
2008 if (scale < 1.0)
2009 {
2010 return *GEGL_RECTANGLE (x1 - pad,
2011 y1 - pad,
2012 x2 - x1 + 2 * pad,
2013 y2 - y1 + 2 * pad);
2014 }
2015 else
2016 {
2017 return *GEGL_RECTANGLE (x1,
2018 y1,
2019 x2 - x1,
2020 y2 - y1);
2021 }
2022 }
2023 }
2024
2025 static inline void
_gegl_buffer_get_unlocked(GeglBuffer * buffer,gdouble scale,const GeglRectangle * rect,const Babl * format,gpointer dest_buf,gint rowstride,GeglAbyssPolicy flags)2026 _gegl_buffer_get_unlocked (GeglBuffer *buffer,
2027 gdouble scale,
2028 const GeglRectangle *rect,
2029 const Babl *format,
2030 gpointer dest_buf,
2031 gint rowstride,
2032 GeglAbyssPolicy flags)
2033 {
2034 GeglAbyssPolicy repeat_mode = flags & 0x7; /* mask off interpolation from repeat mode part of flags */
2035
2036 g_return_if_fail (scale > 0.0f);
2037
2038 if (! rect && GEGL_FLOAT_EQUAL (scale, 1.0))
2039 rect = &buffer->extent;
2040
2041 g_return_if_fail (rect != NULL);
2042
2043 if (G_UNLIKELY (gegl_rectangle_is_empty (rect)))
2044 return;
2045
2046 g_return_if_fail (dest_buf != NULL);
2047
2048 if (! format)
2049 format = buffer->soft_format;
2050
2051 if (gegl_buffer_ext_flush)
2052 gegl_buffer_ext_flush (buffer, rect);
2053
2054 if (G_UNLIKELY (scale == 1.0 &&
2055 rect->width == 1))
2056 {
2057 if (rect->height == 1)
2058 {
2059 gegl_buffer_get_pixel (buffer, rect->x, rect->y, format, dest_buf,
2060 repeat_mode);
2061 }
2062 else
2063 {
2064 if (buffer->soft_format == format ||
2065 rowstride != babl_format_get_bytes_per_pixel (format))
2066 {
2067 gegl_buffer_iterate_read_dispatch (buffer, rect, dest_buf,
2068 rowstride, format, 0, repeat_mode);
2069 }
2070 else
2071 {
2072 /* first fetch all pixels to a temporary buffer */
2073 gint bpp = babl_format_get_bytes_per_pixel (buffer->soft_format);
2074 uint8_t tmp[rect->height * bpp];
2075 gegl_buffer_iterate_read_dispatch (buffer, rect, &tmp[0],
2076 bpp, buffer->soft_format, 0, repeat_mode);
2077 /* then convert in a single shot */
2078 babl_process (babl_fish (buffer->soft_format, format),
2079 &tmp[0], dest_buf, rect->height);
2080 }
2081 }
2082 return;
2083 }
2084
2085 if (GEGL_FLOAT_EQUAL (scale, 1.0))
2086 {
2087 gegl_buffer_iterate_read_dispatch (buffer, rect, dest_buf, rowstride,
2088 format, 0, repeat_mode);
2089 return;
2090 }
2091 else
2092 {
2093 gint chunk_height;
2094 GeglRectangle rect2 = *rect;
2095 gint bpp = babl_format_get_bytes_per_pixel (format);
2096 gint ystart = rect->y;
2097 float scale_orig = scale;
2098 gint level = 0;
2099 void *sample_buf;
2100 gint x1 = int_floorf (rect->x / scale_orig + GEGL_SCALE_EPSILON);
2101 gint x2 = int_ceilf ((rect->x + rect->width) / scale_orig - GEGL_SCALE_EPSILON);
2102 int max_bytes_per_row = ((rect->width+1) * bpp * 2);
2103 int allocated = 0;
2104 gint interpolation = (flags & GEGL_BUFFER_FILTER_ALL);
2105 gint factor = 1;
2106
2107 while (scale <= 0.5)
2108 {
2109 x1 = 0 < x1 ? x1 / 2 : (x1 - 1) / 2;
2110 x2 = 0 < x2 ? (x2 + 1) / 2 : x2 / 2;
2111 scale *= 2;
2112 factor *= 2;
2113 level++;
2114 }
2115
2116 if (GEGL_FLOAT_EQUAL (scale, 1.0))
2117 {
2118 GeglRectangle rect0;
2119
2120 rect0.x = int_floorf (rect->x / scale_orig + GEGL_SCALE_EPSILON);
2121 rect0.y = int_floorf (rect->y / scale_orig + GEGL_SCALE_EPSILON);
2122 rect0.width = int_ceilf ((rect->x + rect->width) / scale_orig -
2123 GEGL_SCALE_EPSILON) -
2124 rect0.x;
2125 rect0.height = int_ceilf ((rect->y + rect->height) / scale_orig -
2126 GEGL_SCALE_EPSILON) -
2127 rect0.y;
2128
2129 gegl_buffer_iterate_read_dispatch (buffer, &rect0,
2130 dest_buf, rowstride,
2131 format, level, repeat_mode);
2132 return;
2133 }
2134
2135 chunk_height = (1024 * 128) / max_bytes_per_row;
2136
2137 if (chunk_height < 4)
2138 chunk_height = 4;
2139
2140 rect2.y = ystart;
2141 rect2.height = chunk_height;
2142 if (rect2.y + rect2.height > rect->y + rect->height)
2143 {
2144 rect2.height = (rect->y + rect->height) - rect2.y;
2145 chunk_height = rect2.height;
2146 }
2147
2148 allocated = max_bytes_per_row * ((chunk_height+1) * 2);
2149
2150 if (interpolation == GEGL_BUFFER_FILTER_AUTO)
2151 {
2152 /* with no specified interpolation we aim for a trade-off where
2153 100-200% ends up using box-filter - which is a better transition
2154 to nearest neighbor which happens beyond 200% further below.
2155 */
2156 if (scale >= 2.0)
2157 interpolation = GEGL_BUFFER_FILTER_NEAREST;
2158 else if (scale > 1.0)
2159 {
2160 interpolation = GEGL_BUFFER_FILTER_BOX;
2161 }
2162 else
2163 interpolation = GEGL_BUFFER_FILTER_BILINEAR;
2164 }
2165
2166 sample_buf = gegl_scratch_alloc (allocated);
2167
2168 while (rect2.width > 0 && rect2.height > 0)
2169 {
2170 GeglRectangle sample_rect;
2171 gint buf_width, buf_height;
2172 gint y1 = int_floorf (rect2.y / scale_orig + GEGL_SCALE_EPSILON);
2173 gint y2 = int_ceilf ((rect2.y + rect2.height) / scale_orig - GEGL_SCALE_EPSILON);
2174 scale = scale_orig;
2175
2176 while (scale <= 0.5)
2177 {
2178 y1 = 0 < y1 ? y1 / 2 : (y1 - 1) / 2;
2179 y2 = 0 < y2 ? (y2 + 1) / 2 : y2 / 2;
2180 scale *= 2;
2181 }
2182
2183 if (rowstride == GEGL_AUTO_ROWSTRIDE)
2184 rowstride = rect2.width * bpp;
2185
2186 /* this is the level where we split and chew through a small temp-buf worth of data
2187 * possibly managing to keep things in L2 cache
2188 */
2189
2190 sample_rect.x = factor * x1;
2191 sample_rect.y = factor * y1;
2192 sample_rect.width = factor * (x2 - x1);
2193 sample_rect.height = factor * (y2 - y1);
2194 buf_width = x2 - x1;
2195 buf_height = y2 - y1;
2196
2197
2198 if (buf_height && buf_width)
2199 switch(interpolation)
2200 {
2201 case GEGL_BUFFER_FILTER_NEAREST:
2202
2203 gegl_buffer_iterate_read_dispatch (buffer, &sample_rect,
2204 (guchar*)sample_buf,
2205 buf_width * bpp,
2206 format, level, repeat_mode);
2207 sample_rect.x = x1;
2208 sample_rect.y = y1;
2209 sample_rect.width = x2 - x1;
2210 sample_rect.height = y2 - y1;
2211
2212 gegl_resample_nearest (dest_buf,
2213 sample_buf,
2214 &rect2,
2215 &sample_rect,
2216 buf_width * bpp,
2217 scale,
2218 bpp,
2219 rowstride);
2220 break;
2221 case GEGL_BUFFER_FILTER_BILINEAR:
2222 buf_width += 1;
2223 buf_height += 1;
2224
2225 /* fill the regions of the buffer outside the sampled area with
2226 * zeros, since they may be involved in the arithmetic. even
2227 * though their actual value should have no, or negligible, effect,
2228 * they must at least be finite, when dealing with float formats.
2229 */
2230 {
2231 guchar *p = sample_buf;
2232 gint y;
2233
2234 for (y = 0; y < buf_height - 1; y++)
2235 {
2236 memset (p + (buf_width - 1) * bpp, 0, bpp);
2237
2238 p += buf_width * bpp;
2239 }
2240
2241 memset (p, 0, buf_width * bpp);
2242 }
2243
2244 gegl_buffer_iterate_read_dispatch (buffer, &sample_rect,
2245 (guchar*)sample_buf,
2246 buf_width * bpp,
2247 format, level, repeat_mode);
2248
2249 sample_rect.x = x1;
2250 sample_rect.y = y1;
2251 sample_rect.width = x2 - x1 + 1;
2252 sample_rect.height = y2 - y1 + 1;
2253
2254 gegl_resample_bilinear (dest_buf,
2255 sample_buf,
2256 &rect2,
2257 &sample_rect,
2258 buf_width * bpp,
2259 scale,
2260 format,
2261 rowstride);
2262 break;
2263 case GEGL_BUFFER_FILTER_BOX:
2264 default:
2265 {
2266 gint offset;
2267 buf_width += 2;
2268 buf_height += 2;
2269 offset = (buf_width + 1) * bpp;
2270
2271 /* fill the regions of the buffer outside the sampled area with
2272 * zeros, since they may be involved in the arithmetic. even
2273 * though their actual value should have no, or negligible,
2274 * effect, they must at least be finite, when dealing with float
2275 * formats.
2276 */
2277 {
2278 guchar *p = sample_buf;
2279 gint y;
2280
2281 memset (p, 0, (buf_width - 1) * bpp);
2282
2283 for (y = 0; y < buf_height - 1; y++)
2284 {
2285 memset (p + (buf_width - 1) * bpp, 0, 2 * bpp);
2286
2287 p += buf_width * bpp;
2288 }
2289
2290 memset (p + bpp, 0, (buf_width - 1) * bpp);
2291 }
2292
2293 gegl_buffer_iterate_read_dispatch (buffer, &sample_rect,
2294 (guchar*)sample_buf + offset,
2295 buf_width * bpp,
2296 format, level, repeat_mode);
2297
2298 sample_rect.x = x1 - 1;
2299 sample_rect.y = y1 - 1;
2300 sample_rect.width = x2 - x1 + 2;
2301 sample_rect.height = y2 - y1 + 2;
2302
2303 gegl_resample_boxfilter (dest_buf,
2304 sample_buf,
2305 &rect2,
2306 &sample_rect,
2307 buf_width * bpp,
2308 scale,
2309 format,
2310 rowstride);
2311 }
2312 break;
2313 }
2314
2315 dest_buf = ((guchar*)dest_buf) + rowstride * rect2.height;
2316 ystart+=rect2.height;
2317 rect2.y = ystart;
2318 rect2.height = chunk_height;
2319 if (rect2.y + rect2.height > rect->y + rect->height)
2320 rect2.height = (rect->y + rect->height) - rect2.y;
2321
2322 }
2323
2324 gegl_scratch_free (sample_buf);
2325 }
2326 }
2327
2328 void
gegl_buffer_get_unlocked(GeglBuffer * buffer,gdouble scale,const GeglRectangle * rect,const Babl * format,gpointer dest_buf,gint rowstride,GeglAbyssPolicy repeat_mode)2329 gegl_buffer_get_unlocked (GeglBuffer *buffer,
2330 gdouble scale,
2331 const GeglRectangle *rect,
2332 const Babl *format,
2333 gpointer dest_buf,
2334 gint rowstride,
2335 GeglAbyssPolicy repeat_mode)
2336 {
2337 return _gegl_buffer_get_unlocked (buffer, scale, rect, format, dest_buf, rowstride, repeat_mode);
2338 }
2339
2340 void
gegl_buffer_get(GeglBuffer * buffer,const GeglRectangle * rect,gdouble scale,const Babl * format,gpointer dest_buf,gint rowstride,GeglAbyssPolicy repeat_mode)2341 gegl_buffer_get (GeglBuffer *buffer,
2342 const GeglRectangle *rect,
2343 gdouble scale,
2344 const Babl *format,
2345 gpointer dest_buf,
2346 gint rowstride,
2347 GeglAbyssPolicy repeat_mode)
2348 {
2349 g_return_if_fail (GEGL_IS_BUFFER (buffer));
2350 gegl_buffer_lock (buffer);
2351 _gegl_buffer_get_unlocked (buffer, scale, rect, format, dest_buf, rowstride, repeat_mode);
2352 gegl_buffer_unlock (buffer);
2353 }
2354
2355 static void
gegl_buffer_copy2(GeglBuffer * src,const GeglRectangle * src_rect,GeglAbyssPolicy repeat_mode,GeglBuffer * dst,const GeglRectangle * dst_rect)2356 gegl_buffer_copy2 (GeglBuffer *src,
2357 const GeglRectangle *src_rect,
2358 GeglAbyssPolicy repeat_mode,
2359 GeglBuffer *dst,
2360 const GeglRectangle *dst_rect)
2361 {
2362 GeglBufferIterator *i;
2363 gint offset_x = src_rect->x - dst_rect->x;
2364 gint offset_y = src_rect->y - dst_rect->y;
2365
2366 i = gegl_buffer_iterator_new (dst, dst_rect, 0, dst->soft_format,
2367 GEGL_ACCESS_WRITE | GEGL_ITERATOR_NO_NOTIFY,
2368 repeat_mode, 1);
2369 while (gegl_buffer_iterator_next (i))
2370 {
2371 GeglRectangle src_rect = i->items[0].roi;
2372 src_rect.x += offset_x;
2373 src_rect.y += offset_y;
2374 gegl_buffer_iterate_read_dispatch (src, &src_rect, i->items[0].data, 0,
2375 dst->soft_format, 0, repeat_mode);
2376 }
2377 }
2378
2379 void
gegl_buffer_copy(GeglBuffer * src,const GeglRectangle * src_rect,GeglAbyssPolicy repeat_mode,GeglBuffer * dst,const GeglRectangle * dst_rect)2380 gegl_buffer_copy (GeglBuffer *src,
2381 const GeglRectangle *src_rect,
2382 GeglAbyssPolicy repeat_mode,
2383 GeglBuffer *dst,
2384 const GeglRectangle *dst_rect)
2385 {
2386 GeglRectangle real_src_rect;
2387 GeglRectangle real_dst_rect;
2388
2389 g_return_if_fail (GEGL_IS_BUFFER (src));
2390 g_return_if_fail (GEGL_IS_BUFFER (dst));
2391
2392 if (!src_rect)
2393 {
2394 src_rect = gegl_buffer_get_extent (src);
2395 }
2396 if (G_UNLIKELY (src_rect->width <= 0 ||
2397 src_rect->height <= 0))
2398 return;
2399
2400 if (!dst_rect)
2401 {
2402 dst_rect = src_rect;
2403 }
2404
2405 real_dst_rect = *dst_rect;
2406 real_dst_rect.width = src_rect->width;
2407 real_dst_rect.height = src_rect->height;
2408
2409 if (G_UNLIKELY (! gegl_rectangle_intersect (&real_dst_rect, &real_dst_rect, &dst->abyss)))
2410 return;
2411
2412 real_src_rect = real_dst_rect;
2413 real_src_rect.x += src_rect->x - dst_rect->x;
2414 real_src_rect.y += src_rect->y - dst_rect->y;
2415
2416 src_rect = &real_src_rect;
2417 dst_rect = &real_dst_rect;
2418
2419 if (! gegl_rectangle_intersect (NULL, src_rect, &src->abyss))
2420 {
2421 switch (repeat_mode)
2422 {
2423 case GEGL_ABYSS_CLAMP:
2424 case GEGL_ABYSS_LOOP:
2425 if (! gegl_rectangle_is_empty (&src->abyss))
2426 break;
2427
2428 /* fall through */
2429
2430 case GEGL_ABYSS_NONE:
2431 {
2432 const gfloat color[4] = {0.0f, 0.0f, 0.0f, 0.0f};
2433
2434 gegl_buffer_set_color_from_pixel (dst, dst_rect, color,
2435 gegl_babl_rgba_linear_float ());
2436
2437 return;
2438 }
2439
2440 case GEGL_ABYSS_BLACK:
2441 {
2442 const gfloat color[4] = {0.0f, 0.0f, 0.0f, 1.0f};
2443
2444 gegl_buffer_set_color_from_pixel (dst, dst_rect, color,
2445 gegl_babl_rgba_linear_float ());
2446
2447 return;
2448 }
2449
2450 case GEGL_ABYSS_WHITE:
2451 {
2452 const gfloat color[4] = {1.0f, 1.0f, 1.0f, 1.0f};
2453
2454 gegl_buffer_set_color_from_pixel (dst, dst_rect, color,
2455 gegl_babl_rgba_linear_float ());
2456
2457 return;
2458 }
2459
2460 default:
2461 break;
2462 }
2463 }
2464
2465 if (src->soft_format == dst->soft_format &&
2466 src_rect->width >= src->tile_width &&
2467 src_rect->height >= src->tile_height &&
2468 src->tile_width == dst->tile_width &&
2469 src->tile_height == dst->tile_height &&
2470 !g_object_get_data (G_OBJECT (dst), "is-linear") &&
2471 gegl_buffer_scan_compatible (src, src_rect->x, src_rect->y,
2472 dst, dst_rect->x, dst_rect->y))
2473 {
2474 gint tile_width = dst->tile_width;
2475 gint tile_height = dst->tile_height;
2476
2477 GeglRectangle cow_rect;
2478 gint rem;
2479
2480 gegl_rectangle_intersect (&cow_rect, src_rect, &src->abyss);
2481
2482 cow_rect.x += dst_rect->x - src_rect->x;
2483 cow_rect.y += dst_rect->y - src_rect->y;
2484
2485 /* adjust origin to match the start of tile alignment */
2486 rem = (cow_rect.x + dst->shift_x) % tile_width;
2487 if (rem > 0)
2488 rem -= tile_width;
2489 cow_rect.x -= rem;
2490 cow_rect.width += rem;
2491
2492 rem = (cow_rect.y + dst->shift_y) % tile_height;
2493 if (rem > 0)
2494 rem -= tile_height;
2495 cow_rect.y -= rem;
2496 cow_rect.height += rem;
2497
2498 /* adjust size of rect to match multiple of tiles */
2499 cow_rect.width -= cow_rect.width % tile_width;
2500 cow_rect.height -= cow_rect.height % tile_height;
2501
2502 if (cow_rect.width > 0 && cow_rect.height > 0)
2503 {
2504 GeglRectangle top, bottom, left, right;
2505
2506 /* iterate over rectangle that can be cow copied, duplicating
2507 * one and one tile
2508 */
2509 {
2510 /* first we do a dumb copy,. but with fetched tiles */
2511 GeglTileSource *source = GEGL_TILE_SOURCE (src->tile_storage);
2512 GeglTileHandlerCache *cache = dst->tile_storage->cache;
2513 gboolean fast_copy;
2514 gint dst_x, dst_y;
2515
2516 /* we only attempt performing a fast copy, using the TILE_COPY
2517 * command, if the source buffer doesn't have any user-provided
2518 * tile handlers. the problem with user-provided tile handlers is
2519 * that they might intenrally track the validity of tile contents,
2520 * in a way that's opaque to gegl, and the only way to know for
2521 * sure a given tile is valid, is to fetch it using TILE_GET.
2522 *
2523 * in the future, it might make sense to relax this condition, by
2524 * adding some api, or changing the requirements of tile handlers.
2525 */
2526 fast_copy = (src->tile_storage->n_user_handlers == 0);
2527
2528 if (src->tile_storage < dst->tile_storage)
2529 {
2530 g_rec_mutex_lock (&src->tile_storage->mutex);
2531 g_rec_mutex_lock (&dst->tile_storage->mutex);
2532 }
2533 else
2534 {
2535 g_rec_mutex_lock (&dst->tile_storage->mutex);
2536 g_rec_mutex_lock (&src->tile_storage->mutex);
2537 }
2538
2539 for (dst_y = cow_rect.y + dst->shift_y; dst_y < cow_rect.y + dst->shift_y + cow_rect.height; dst_y += tile_height)
2540 for (dst_x = cow_rect.x + dst->shift_x; dst_x < cow_rect.x + dst->shift_x + cow_rect.width; dst_x += tile_width)
2541 {
2542 gint src_x, src_y;
2543 gint stx, sty, dtx, dty;
2544
2545 src_x = dst_x + (src_rect->x - dst_rect->x) + (src->shift_x - dst->shift_x);
2546 src_y = dst_y + (src_rect->y - dst_rect->y) + (src->shift_y - dst->shift_y);
2547
2548 stx = gegl_tile_indice (src_x, tile_width);
2549 sty = gegl_tile_indice (src_y, tile_height);
2550 dtx = gegl_tile_indice (dst_x, tile_width);
2551 dty = gegl_tile_indice (dst_y, tile_height);
2552
2553 if (! fast_copy ||
2554 ! gegl_tile_source_copy (source, stx, sty, 0,
2555 dst, dtx, dty, 0))
2556 {
2557 GeglTile *src_tile;
2558 GeglTile *dst_tile;
2559
2560 src_tile = gegl_tile_source_get_tile (source, stx, sty, 0);
2561
2562 dst_tile = gegl_tile_dup (src_tile);
2563 dst_tile->tile_storage = dst->tile_storage;
2564 dst_tile->x = dtx;
2565 dst_tile->y = dty;
2566 dst_tile->z = 0;
2567
2568 gegl_tile_handler_cache_insert (cache, dst_tile, dtx, dty, 0);
2569
2570 gegl_tile_unref (dst_tile);
2571 gegl_tile_unref (src_tile);
2572 }
2573 }
2574
2575 g_rec_mutex_unlock (&src->tile_storage->mutex);
2576
2577 gegl_tile_handler_damage_rect (
2578 GEGL_TILE_HANDLER (dst->tile_storage),
2579 GEGL_RECTANGLE (cow_rect.x + dst->shift_x,
2580 cow_rect.y + dst->shift_y,
2581 cow_rect.width,
2582 cow_rect.height));
2583
2584 g_rec_mutex_unlock (&dst->tile_storage->mutex);
2585 }
2586
2587 top = *dst_rect;
2588 top.height = (cow_rect.y - dst_rect->y);
2589
2590
2591 left = *dst_rect;
2592 left.y = cow_rect.y;
2593 left.height = cow_rect.height;
2594 left.width = (cow_rect.x - dst_rect->x);
2595
2596 bottom = *dst_rect;
2597 bottom.y = (cow_rect.y + cow_rect.height);
2598 bottom.height = (dst_rect->y + dst_rect->height) -
2599 (cow_rect.y + cow_rect.height);
2600
2601 if (bottom.height < 0)
2602 bottom.height = 0;
2603
2604 right = *dst_rect;
2605 right.x = (cow_rect.x + cow_rect.width);
2606 right.width = (dst_rect->x + dst_rect->width) -
2607 (cow_rect.x + cow_rect.width);
2608 right.y = cow_rect.y;
2609 right.height = cow_rect.height;
2610
2611 if (right.width < 0)
2612 right.width = 0;
2613
2614 if (top.height)
2615 gegl_buffer_copy2 (src,
2616 GEGL_RECTANGLE (src_rect->x + (top.x-dst_rect->x),
2617 src_rect->y + (top.y-dst_rect->y),
2618 top.width, top.height),
2619 repeat_mode, dst, &top);
2620 if (bottom.height)
2621 gegl_buffer_copy2 (src,
2622 GEGL_RECTANGLE (src_rect->x + (bottom.x-dst_rect->x),
2623 src_rect->y + (bottom.y-dst_rect->y),
2624 bottom.width, bottom.height),
2625 repeat_mode, dst, &bottom);
2626 if (left.width && left.height)
2627 gegl_buffer_copy2 (src,
2628 GEGL_RECTANGLE (src_rect->x + (left.x-dst_rect->x),
2629 src_rect->y + (left.y-dst_rect->y),
2630 left.width, left.height),
2631 repeat_mode, dst, &left);
2632 if (right.width && right.height)
2633 gegl_buffer_copy2 (src,
2634 GEGL_RECTANGLE (src_rect->x + (right.x-dst_rect->x),
2635 src_rect->y + (right.y-dst_rect->y),
2636 right.width, right.height),
2637 repeat_mode, dst, &right);
2638 }
2639 else
2640 {
2641 gegl_buffer_copy2 (src, src_rect, repeat_mode, dst, dst_rect);
2642 }
2643 }
2644 else
2645 {
2646 gegl_buffer_copy2 (src, src_rect, repeat_mode, dst, dst_rect);
2647 }
2648
2649 gegl_buffer_emit_changed_signal (dst, dst_rect);
2650 }
2651
2652 typedef void (* GeglBufferTileFunc) (GeglBuffer *buffer,
2653 gint tile_x,
2654 gint tile_y,
2655 gpointer data);
2656 typedef void (* GeglBufferRectFunc) (GeglBuffer *buffer,
2657 const GeglRectangle *rect,
2658 gpointer data);
2659
2660 static void
gegl_buffer_foreach_tile(GeglBuffer * buffer,const GeglRectangle * rect,GeglBufferTileFunc tile_func,GeglBufferRectFunc rect_func,gpointer data)2661 gegl_buffer_foreach_tile (GeglBuffer *buffer,
2662 const GeglRectangle *rect,
2663 GeglBufferTileFunc tile_func,
2664 GeglBufferRectFunc rect_func,
2665 gpointer data)
2666 {
2667 if (! rect)
2668 rect = gegl_buffer_get_extent (buffer);
2669
2670 if (G_UNLIKELY (rect->width <= 0 || rect->height <= 0))
2671 return;
2672
2673 #if 1
2674 /* cow for clearing is currently broken */
2675 if (rect->width >= buffer->tile_width &&
2676 rect->height >= buffer->tile_height &&
2677 ! g_object_get_data (G_OBJECT (buffer), "is-linear"))
2678 {
2679 gint tile_width = buffer->tile_width;
2680 gint tile_height = buffer->tile_height;
2681
2682 GeglRectangle tile_rect = *rect;
2683 gint rem;
2684
2685 /* shift rect to tile coordinate system */
2686 tile_rect.x += buffer->shift_x;
2687 tile_rect.y += buffer->shift_y;
2688
2689 /* adjust origin to match the start of tile alignment */
2690 rem = tile_rect.x % tile_width;
2691 if (rem > 0)
2692 rem -= tile_width;
2693 tile_rect.x -= rem;
2694 tile_rect.width += rem;
2695
2696 rem = tile_rect.y % tile_height;
2697 if (rem > 0)
2698 rem -= tile_height;
2699 tile_rect.y -= rem;
2700 tile_rect.height += rem;
2701
2702 /* adjust size of rect to match multiple of tiles */
2703 tile_rect.width -= tile_rect.width % tile_width;
2704 tile_rect.height -= tile_rect.height % tile_height;
2705
2706 if (tile_rect.width > 0 && tile_rect.height > 0)
2707 {
2708 GeglRectangle top, bottom, left, right;
2709
2710 /* iterate over the tile rectangle */
2711 {
2712 gint x, y;
2713
2714 g_rec_mutex_lock (&buffer->tile_storage->mutex);
2715
2716 for (y = tile_rect.y;
2717 y < tile_rect.y + tile_rect.height;
2718 y += tile_height)
2719 {
2720 for (x = tile_rect.x;
2721 x < tile_rect.x + tile_rect.width;
2722 x += tile_width)
2723 {
2724 gint tile_x, tile_y;
2725
2726 tile_x = gegl_tile_indice (x, tile_width);
2727 tile_y = gegl_tile_indice (y, tile_height);
2728
2729 tile_func (buffer, tile_x, tile_y, data);
2730 }
2731 }
2732
2733 gegl_tile_handler_damage_rect (
2734 GEGL_TILE_HANDLER (buffer->tile_storage),
2735 &tile_rect);
2736
2737 g_rec_mutex_unlock (&buffer->tile_storage->mutex);
2738 }
2739
2740 /* shift rect to buffer coordinate system */
2741 tile_rect.x -= buffer->shift_x;
2742 tile_rect.y -= buffer->shift_y;
2743
2744 top = *rect;
2745 top.height = (tile_rect.y - rect->y);
2746
2747
2748 left = *rect;
2749 left.y = tile_rect.y;
2750 left.height = tile_rect.height;
2751 left.width = (tile_rect.x - rect->x);
2752
2753 bottom = *rect;
2754 bottom.y = (tile_rect.y + tile_rect.height);
2755 bottom.height = (rect->y + rect->height) -
2756 (tile_rect.y + tile_rect.height);
2757
2758 if (bottom.height < 0)
2759 bottom.height = 0;
2760
2761 right = *rect;
2762 right.x = (tile_rect.x + tile_rect.width);
2763 right.width = (rect->x + rect->width) -
2764 (tile_rect.x + tile_rect.width);
2765 right.y = tile_rect.y;
2766 right.height = tile_rect.height;
2767
2768 if (right.width < 0)
2769 right.width = 0;
2770
2771 if (top.height) rect_func (buffer, &top, data);
2772 if (bottom.height) rect_func (buffer, &bottom, data);
2773 if (left.width && left.height) rect_func (buffer, &left, data);
2774 if (right.width && right.height) rect_func (buffer, &right, data);
2775 }
2776 else
2777 {
2778 rect_func (buffer, rect, data);
2779 }
2780 }
2781 else
2782 #endif
2783 {
2784 rect_func (buffer, rect, data);
2785 }
2786
2787 gegl_buffer_emit_changed_signal (buffer, rect);
2788 }
2789
2790 static void
gegl_buffer_clear_tile(GeglBuffer * dst,gint tile_x,gint tile_y,gpointer data)2791 gegl_buffer_clear_tile (GeglBuffer *dst,
2792 gint tile_x,
2793 gint tile_y,
2794 gpointer data)
2795 {
2796 if (dst->initialized)
2797 {
2798 gegl_tile_handler_cache_remove (dst->tile_storage->cache,
2799 tile_x, tile_y, 0);
2800
2801 gegl_tile_handler_source_command (dst->tile_storage->cache,
2802 GEGL_TILE_VOID,
2803 tile_x, tile_y, 0, NULL);
2804 }
2805 else
2806 {
2807 GeglTile *tile;
2808
2809 tile = gegl_tile_handler_empty_new_tile (dst->tile_storage->tile_size);
2810
2811 gegl_tile_handler_cache_insert (dst->tile_storage->cache, tile,
2812 tile_x, tile_y, 0);
2813
2814 gegl_tile_unref (tile);
2815 }
2816 }
2817
2818 static void
gegl_buffer_clear_rect(GeglBuffer * dst,const GeglRectangle * dst_rect,gpointer data)2819 gegl_buffer_clear_rect (GeglBuffer *dst,
2820 const GeglRectangle *dst_rect,
2821 gpointer data)
2822 {
2823 GeglBufferIterator *i;
2824 gint pxsize;
2825
2826 pxsize = babl_format_get_bytes_per_pixel (dst->soft_format);
2827
2828 if (gegl_buffer_ext_invalidate)
2829 {
2830 gegl_buffer_ext_invalidate (dst, dst_rect);
2831 }
2832
2833 i = gegl_buffer_iterator_new (dst, dst_rect, 0, dst->soft_format,
2834 GEGL_ACCESS_WRITE | GEGL_ITERATOR_NO_NOTIFY,
2835 GEGL_ABYSS_NONE, 1);
2836 while (gegl_buffer_iterator_next (i))
2837 {
2838 memset (((guchar*)(i->items[0].data)), 0, i->length * pxsize);
2839 }
2840 }
2841
2842 void
gegl_buffer_clear(GeglBuffer * dst,const GeglRectangle * dst_rect)2843 gegl_buffer_clear (GeglBuffer *dst,
2844 const GeglRectangle *dst_rect)
2845 {
2846 g_return_if_fail (GEGL_IS_BUFFER (dst));
2847
2848 gegl_buffer_foreach_tile (dst, dst_rect,
2849 gegl_buffer_clear_tile,
2850 gegl_buffer_clear_rect,
2851 NULL);
2852 }
2853
2854 void
gegl_buffer_set_pattern(GeglBuffer * buffer,const GeglRectangle * rect,GeglBuffer * pattern,gint x_offset,gint y_offset)2855 gegl_buffer_set_pattern (GeglBuffer *buffer,
2856 const GeglRectangle *rect,
2857 GeglBuffer *pattern,
2858 gint x_offset,
2859 gint y_offset)
2860 {
2861 const GeglRectangle *pattern_extent;
2862 const Babl *buffer_format;
2863 GeglRectangle roi; /* the rect if not NULL, else the whole buffer */
2864 GeglRectangle pattern_data_extent; /* pattern_extent clamped to rect */
2865 GeglRectangle extended_data_extent; /* many patterns to avoid copying too small chunks of data */
2866 gint bpp;
2867 gint x, y;
2868 gint rowstride;
2869 gpointer pattern_data;
2870
2871 g_return_if_fail (GEGL_IS_BUFFER (buffer));
2872 g_return_if_fail (GEGL_IS_BUFFER (pattern));
2873
2874 if (rect != NULL)
2875 roi = *rect;
2876 else
2877 roi = *gegl_buffer_get_extent (buffer);
2878
2879 pattern_extent = gegl_buffer_get_extent (pattern);
2880 buffer_format = gegl_buffer_get_format (buffer);
2881
2882 pattern_data_extent.x = - x_offset + roi.x;
2883 pattern_data_extent.y = - y_offset + roi.y;
2884 pattern_data_extent.width = MIN (pattern_extent->width, roi.width);
2885 pattern_data_extent.height = MIN (pattern_extent->height, roi.height);
2886
2887 /* Sanity */
2888 if (pattern_data_extent.width < 1 || pattern_data_extent.height < 1)
2889 return;
2890
2891 bpp = babl_format_get_bytes_per_pixel (buffer_format);
2892
2893 extended_data_extent = pattern_data_extent;
2894
2895 /* Avoid gegl_buffer_set on too small chunks */
2896 extended_data_extent.width *= (buffer->tile_width * 2 +
2897 (extended_data_extent.width - 1)) /
2898 extended_data_extent.width;
2899 extended_data_extent.width = MIN (extended_data_extent.width, roi.width);
2900
2901 extended_data_extent.height *= (buffer->tile_height * 2 +
2902 (extended_data_extent.height - 1)) /
2903 extended_data_extent.height;
2904 extended_data_extent.height = MIN (extended_data_extent.height, roi.height);
2905
2906 /* XXX: Bad taste, the pattern needs to be small enough.
2907 * See Bug 712814 for an alternative malloc-free implementation */
2908 pattern_data = gegl_scratch_alloc (extended_data_extent.width *
2909 extended_data_extent.height *
2910 bpp);
2911
2912 rowstride = extended_data_extent.width * bpp;
2913
2914 /* only do babl conversions once on the whole pattern */
2915 gegl_buffer_get (pattern, &pattern_data_extent, 1.0,
2916 buffer_format, pattern_data,
2917 rowstride, GEGL_ABYSS_LOOP);
2918
2919 /* fill the remaining space by duplicating the small pattern */
2920 for (y = 0; y < pattern_data_extent.height; y++)
2921 for (x = pattern_extent->width;
2922 x < extended_data_extent.width;
2923 x *= 2)
2924 {
2925 guchar *src = ((guchar*) pattern_data) + y * rowstride;
2926 guchar *dst = src + x * bpp;
2927 gint size = bpp * MIN (extended_data_extent.width - x, x);
2928 memcpy (dst, src, size);
2929 }
2930
2931 for (y = pattern_extent->height;
2932 y < extended_data_extent.height;
2933 y *= 2)
2934 {
2935 guchar *src = ((guchar*) pattern_data);
2936 guchar *dst = src + y * rowstride;
2937 gint size = rowstride * MIN (extended_data_extent.height - y, y);
2938 memcpy (dst, src, size);
2939 }
2940
2941 /* Now fill the acutal buffer */
2942 for (y = roi.y; y < roi.y + roi.height; y += extended_data_extent.height)
2943 for (x = roi.x; x < roi.x + roi.width; x += extended_data_extent.width)
2944 {
2945 GeglRectangle dest_rect = {x, y,
2946 extended_data_extent.width,
2947 extended_data_extent.height};
2948
2949 gegl_rectangle_intersect (&dest_rect, &dest_rect, &roi);
2950
2951 gegl_buffer_set (buffer, &dest_rect, 0, buffer_format,
2952 pattern_data, rowstride);
2953 }
2954
2955 gegl_scratch_free (pattern_data);
2956 }
2957
2958 typedef struct
2959 {
2960 gconstpointer pixel;
2961 gint bpp;
2962
2963 GeglTile *tile;
2964 } SetColorFromPixelData;
2965
2966 static void
gegl_buffer_set_color_from_pixel_tile(GeglBuffer * dst,gint tile_x,gint tile_y,SetColorFromPixelData * data)2967 gegl_buffer_set_color_from_pixel_tile (GeglBuffer *dst,
2968 gint tile_x,
2969 gint tile_y,
2970 SetColorFromPixelData *data)
2971 {
2972 GeglTile *tile;
2973
2974 if (data->tile)
2975 {
2976 tile = gegl_tile_dup (data->tile);
2977 }
2978 else
2979 {
2980 gint tile_size = dst->tile_storage->tile_size;
2981
2982 if (gegl_memeq_zero (data->pixel, data->bpp))
2983 {
2984 tile = gegl_tile_handler_empty_new_tile (tile_size);
2985 }
2986 else
2987 {
2988 tile = gegl_tile_new (tile_size);
2989
2990 gegl_tile_lock (tile);
2991
2992 gegl_memset_pattern (gegl_tile_get_data (tile),
2993 data->pixel,
2994 data->bpp,
2995 tile_size / data->bpp);
2996
2997 gegl_tile_unlock (tile);
2998 }
2999 }
3000
3001 gegl_tile_handler_cache_insert (dst->tile_storage->cache, tile,
3002 tile_x, tile_y, 0);
3003
3004 if (data->tile)
3005 gegl_tile_unref (tile);
3006 else
3007 data->tile = tile;
3008 }
3009
3010 static void
gegl_buffer_set_color_from_pixel_rect(GeglBuffer * dst,const GeglRectangle * dst_rect,SetColorFromPixelData * data)3011 gegl_buffer_set_color_from_pixel_rect (GeglBuffer *dst,
3012 const GeglRectangle *dst_rect,
3013 SetColorFromPixelData *data)
3014 {
3015 GeglBufferIterator *i;
3016
3017 i = gegl_buffer_iterator_new (dst, dst_rect, 0, dst->soft_format,
3018 GEGL_ACCESS_WRITE | GEGL_ITERATOR_NO_NOTIFY,
3019 GEGL_ABYSS_NONE, 1);
3020 while (gegl_buffer_iterator_next (i))
3021 {
3022 gegl_memset_pattern (i->items[0].data,
3023 data->pixel,
3024 data->bpp,
3025 i->length);
3026 }
3027 }
3028
3029 void
gegl_buffer_set_color_from_pixel(GeglBuffer * dst,const GeglRectangle * dst_rect,gconstpointer pixel,const Babl * pixel_format)3030 gegl_buffer_set_color_from_pixel (GeglBuffer *dst,
3031 const GeglRectangle *dst_rect,
3032 gconstpointer pixel,
3033 const Babl *pixel_format)
3034 {
3035 SetColorFromPixelData data = {};
3036
3037 g_return_if_fail (GEGL_IS_BUFFER (dst));
3038 g_return_if_fail (pixel);
3039 if (pixel_format == NULL)
3040 pixel_format = dst->soft_format;
3041
3042 if (!dst_rect)
3043 {
3044 dst_rect = gegl_buffer_get_extent (dst);
3045 }
3046 if (dst_rect->width <= 0 ||
3047 dst_rect->height <= 0)
3048 return;
3049
3050 data.bpp = babl_format_get_bytes_per_pixel (dst->soft_format);
3051
3052 /* convert the pixel data to the buffer format */
3053 if (pixel_format == dst->soft_format)
3054 {
3055 data.pixel = pixel;
3056 }
3057 else
3058 {
3059 data.pixel = g_alloca (data.bpp);
3060
3061 babl_process (babl_fish (pixel_format, dst->soft_format),
3062 pixel, (gpointer) data.pixel, 1);
3063 }
3064
3065 gegl_buffer_foreach_tile (
3066 dst, dst_rect,
3067 (GeglBufferTileFunc) gegl_buffer_set_color_from_pixel_tile,
3068 (GeglBufferRectFunc) gegl_buffer_set_color_from_pixel_rect,
3069 &data);
3070
3071 if (data.tile)
3072 gegl_tile_unref (data.tile);
3073 }
3074
3075 GeglBuffer *
gegl_buffer_dup(GeglBuffer * buffer)3076 gegl_buffer_dup (GeglBuffer *buffer)
3077 {
3078 GeglBuffer *new_buffer;
3079
3080 g_return_val_if_fail (GEGL_IS_BUFFER (buffer), NULL);
3081
3082 new_buffer = g_object_new (GEGL_TYPE_BUFFER,
3083 "format", buffer->soft_format,
3084 "x", buffer->extent.x,
3085 "y", buffer->extent.y,
3086 "width", buffer->extent.width,
3087 "height", buffer->extent.height,
3088 "abyss-x", buffer->abyss.x,
3089 "abyss-y", buffer->abyss.y,
3090 "abyss-width", buffer->abyss.width,
3091 "abyss-height", buffer->abyss.height,
3092 "shift-x", buffer->shift_x,
3093 "shift-y", buffer->shift_y,
3094 "tile-width", buffer->tile_width,
3095 "tile-height", buffer->tile_height,
3096 NULL);
3097
3098 gegl_buffer_copy (buffer, gegl_buffer_get_extent (buffer), GEGL_ABYSS_NONE,
3099 new_buffer, gegl_buffer_get_extent (buffer));
3100
3101 return new_buffer;
3102 }
3103
3104 /*
3105 * check whether iterations on two buffers starting from the given coordinates with
3106 * the same width and height would be able to run parallell.
3107 */
gegl_buffer_scan_compatible(GeglBuffer * bufferA,gint xA,gint yA,GeglBuffer * bufferB,gint xB,gint yB)3108 gboolean gegl_buffer_scan_compatible (GeglBuffer *bufferA,
3109 gint xA,
3110 gint yA,
3111 GeglBuffer *bufferB,
3112 gint xB,
3113 gint yB)
3114 {
3115 if (bufferA->tile_storage->tile_width !=
3116 bufferB->tile_storage->tile_width)
3117 return FALSE;
3118 if (bufferA->tile_storage->tile_height !=
3119 bufferB->tile_storage->tile_height)
3120 return FALSE;
3121 if ( (abs((bufferA->shift_x+xA) - (bufferB->shift_x+xB))
3122 % bufferA->tile_storage->tile_width) != 0)
3123 return FALSE;
3124 if ( (abs((bufferA->shift_y+yA) - (bufferB->shift_y+yB))
3125 % bufferA->tile_storage->tile_height) != 0)
3126 return FALSE;
3127 return TRUE;
3128 }
3129
3130