From fbaf3c4290d9e1a7a506250a6328102cb9e0189e Mon Sep 17 00:00:00 2001 From: Ell Date: Sat, 14 Mar 2020 16:02:14 +0200 Subject: [PATCH] app: render layer-group preview in chunks In gimp_drawable_get_sub_preview_async(), when the drawable buffer has a validate handler (i.e., when it's a group layer), use a chunk iterator to validate the buffer in chunks, where each chunk is validated in a separate invocation of the async function. This prevents validation from blocking the main thread for too long when the buffer is not already fully validated. (cherry picked from commit 64bf77aed88667d0f7b05205e33a19c50e5f3887) --- app/core/gimpdrawable-preview.c | 62 +++++++++++++++++++++++++-------- 1 file changed, 48 insertions(+), 14 deletions(-) diff --git a/app/core/gimpdrawable-preview.c b/app/core/gimpdrawable-preview.c index 93ff17d742..28ae1e224e 100644 --- a/app/core/gimpdrawable-preview.c +++ b/app/core/gimpdrawable-preview.c @@ -39,6 +39,7 @@ #include "gimp-utils.h" #include "gimpasync.h" #include "gimpchannel.h" +#include "gimpchunkiterator.h" #include "gimpimage.h" #include "gimpimage-color-profile.h" #include "gimpdrawable-preview.h" @@ -51,10 +52,12 @@ typedef struct { - const Babl *format; - GeglBuffer *buffer; - GeglRectangle rect; - gdouble scale; + const Babl *format; + GeglBuffer *buffer; + GeglRectangle rect; + gdouble scale; + + GimpChunkIterator *iter; } SubPreviewData; @@ -84,6 +87,8 @@ sub_preview_data_new (const Babl *format, data->rect = *rect; data->scale = scale; + data->iter = NULL; + return data; } @@ -92,6 +97,9 @@ sub_preview_data_free (SubPreviewData *data) { g_object_unref (data->buffer); + if (data->iter) + gimp_chunk_iterator_stop (data->iter, TRUE); + g_slice_free (SubPreviewData, data); } @@ -340,18 +348,44 @@ gimp_drawable_get_sub_preview_async_func (GimpAsync *async, if (validate) { - GeglRectangle rect; + if (! data->iter) + { + cairo_region_t *region; + cairo_rectangle_int_t rect; - rect.x = floor (data->rect.x / data->scale); - rect.y = floor (data->rect.y / data->scale); - rect.width = ceil ((data->rect.x + data->rect.width) / data->scale) - - rect.x; - rect.height = ceil ((data->rect.x + data->rect.height) / data->scale) - - rect.y; + rect.x = floor (data->rect.x / data->scale); + rect.y = floor (data->rect.y / data->scale); + rect.width = ceil ((data->rect.x + data->rect.width) / + data->scale) - rect.x; + rect.height = ceil ((data->rect.x + data->rect.height) / + data->scale) - rect.y; - gimp_tile_handler_validate_validate (validate, - data->buffer, &rect, - TRUE, TRUE); + region = cairo_region_copy (validate->dirty_region); + + cairo_region_intersect_rectangle (region, &rect); + + data->iter = gimp_chunk_iterator_new (region); + } + + if (gimp_chunk_iterator_next (data->iter)) + { + GeglRectangle rect; + + gimp_tile_handler_validate_begin_validate (validate); + + while (gimp_chunk_iterator_get_rect (data->iter, &rect)) + { + gimp_tile_handler_validate_validate (validate, + data->buffer, &rect, + FALSE, FALSE); + } + + gimp_tile_handler_validate_end_validate (validate); + + return; + } + + data->iter = NULL; } gegl_buffer_get (data->buffer, &data->rect, data->scale,