From 9b341d05bb9926ee6de7aae3d449e2f3031c7b60 Mon Sep 17 00:00:00 2001 From: Michael Natterer Date: Sat, 31 May 2014 01:22:54 +0200 Subject: [PATCH] app: remove GimpArea and use cairo_region_t instead This may or may not remove some logic that avoids drawing tiny update regions, and may or may not improve things or make them worse. Will add code that actually tile-aligns update areas later. --- app/core/Makefile.am | 2 - app/core/core-types.h | 1 - app/core/gimparea.c | 108 ---------------------- app/core/gimparea.h | 39 -------- app/core/gimpprojection.c | 184 ++++++++++++++++++++++---------------- app/display/gimpdisplay.c | 77 ++++++++-------- 6 files changed, 149 insertions(+), 262 deletions(-) delete mode 100644 app/core/gimparea.c delete mode 100644 app/core/gimparea.h diff --git a/app/core/Makefile.am b/app/core/Makefile.am index bc0ef130f0..374b3a7c3a 100644 --- a/app/core/Makefile.am +++ b/app/core/Makefile.am @@ -55,8 +55,6 @@ libappcore_a_sources = \ gimp-user-install.h \ gimp-utils.c \ gimp-utils.h \ - gimparea.c \ - gimparea.h \ gimpbezierdesc.h \ gimpbezierdesc.c \ gimpboundary.c \ diff --git a/app/core/core-types.h b/app/core/core-types.h index 9076c316c0..d1c077be2f 100644 --- a/app/core/core-types.h +++ b/app/core/core-types.h @@ -197,7 +197,6 @@ typedef struct _GimpTagged GimpTagged; /* dummy typedef */ /* non-object types */ -typedef struct _GimpArea GimpArea; typedef struct _GimpBoundSeg GimpBoundSeg; typedef struct _GimpCoords GimpCoords; typedef struct _GimpGradientSegment GimpGradientSegment; diff --git a/app/core/gimparea.c b/app/core/gimparea.c deleted file mode 100644 index 6b6db9279c..0000000000 --- a/app/core/gimparea.c +++ /dev/null @@ -1,108 +0,0 @@ -/* GIMP - The GNU Image Manipulation Program - * Copyright (C) 1995 Spencer Kimball and Peter Mattis - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#include "config.h" - -#include - -#include "core-types.h" - -#include "gimparea.h" - - -#define OVERHEAD 25 /* in units of pixel area */ - - -GimpArea * -gimp_area_new (gint x1, - gint y1, - gint x2, - gint y2) -{ - GimpArea *area = g_slice_new (GimpArea); - - area->x1 = x1; - area->y1 = y1; - area->x2 = x2; - area->y2 = y2; - - return area; -} - -void -gimp_area_free (GimpArea *area) -{ - g_slice_free (GimpArea, area); -} - - -/* - * As far as I can tell, this function takes a GimpArea and unifies it with - * an existing list of GimpAreas, trying to avoid overdraw. [adam] - */ -GSList * -gimp_area_list_process (GSList *list, - GimpArea *area) -{ - GSList *retval; - GSList *l; - - retval = g_slist_prepend (NULL, area); - - for (l = list; l; l = g_slist_next (l)) - { - GimpArea *this = l->data; - gint area1; - gint area2; - gint area3; - - area1 = (area->x2 - area->x1) * (area->y2 - area->y1) + OVERHEAD; - area2 = (this->x2 - this->x1) * (this->y2 - this->y1) + OVERHEAD; - area3 = ((MAX (this->x2, area->x2) - MIN (this->x1, area->x1)) * - (MAX (this->y2, area->y2) - MIN (this->y1, area->y1)) + OVERHEAD); - - if (area1 + area2 < area3) - { - retval = g_slist_prepend (retval, this); - } - else - { - area->x1 = MIN (area->x1, this->x1); - area->y1 = MIN (area->y1, this->y1); - area->x2 = MAX (area->x2, this->x2); - area->y2 = MAX (area->y2, this->y2); - - g_slice_free (GimpArea, this); - } - } - - if (list) - g_slist_free (list); - - return retval; -} - -void -gimp_area_list_free (GSList *areas) -{ - GSList *list; - - for (list = areas; list; list = list->next) - gimp_area_free (list->data); - - g_slist_free (areas); -} diff --git a/app/core/gimparea.h b/app/core/gimparea.h deleted file mode 100644 index 833784ba76..0000000000 --- a/app/core/gimparea.h +++ /dev/null @@ -1,39 +0,0 @@ -/* GIMP - The GNU Image Manipulation Program - * Copyright (C) 1995 Spencer Kimball and Peter Mattis - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -#ifndef __GIMP_AREA_H__ -#define __GIMP_AREA_H__ - - -struct _GimpArea -{ - gint x1, y1, x2, y2; /* area bounds */ -}; - - -GimpArea * gimp_area_new (gint x1, - gint y1, - gint x2, - gint y2); -void gimp_area_free (GimpArea *area); - -GSList * gimp_area_list_process (GSList *list, - GimpArea *area); -void gimp_area_list_free (GSList *list); - - -#endif /* __GIMP_AREA_H__ */ diff --git a/app/core/gimpprojection.c b/app/core/gimpprojection.c index 4a31d066b4..5225d56176 100644 --- a/app/core/gimpprojection.c +++ b/app/core/gimpprojection.c @@ -29,7 +29,6 @@ #include "gimp.h" #include "gimp-utils.h" -#include "gimparea.h" #include "gimpimage.h" #include "gimpmarshal.h" #include "gimppickable.h" @@ -67,14 +66,14 @@ typedef struct _GimpProjectionChunkRender GimpProjectionChunkRender; struct _GimpProjectionChunkRender { - gboolean running; - gint width; - gint height; - gint x; - gint y; - gint base_x; - gint base_y; - GSList *update_areas; /* flushed update areas */ + gboolean running; + gint width; + gint height; + gint x; + gint y; + gint base_x; + gint base_y; + cairo_region_t *update_region; /* flushed update region */ }; @@ -87,7 +86,7 @@ struct _GimpProjectionPrivate GeglBuffer *buffer; gpointer validate_handler; - GSList *update_areas; + cairo_region_t *update_region; GimpProjectionChunkRender chunk_render; guint chunk_render_idle_id; @@ -227,11 +226,17 @@ gimp_projection_finalize (GObject *object) if (proj->priv->chunk_render.running) gimp_projection_chunk_render_stop (proj); - gimp_area_list_free (proj->priv->update_areas); - proj->priv->update_areas = NULL; + if (proj->priv->update_region) + { + cairo_region_destroy (proj->priv->update_region); + proj->priv->update_region = NULL; + } - gimp_area_list_free (proj->priv->chunk_render.update_areas); - proj->priv->chunk_render.update_areas = NULL; + if (proj->priv->chunk_render.update_region) + { + cairo_region_destroy (proj->priv->chunk_render.update_region); + proj->priv->chunk_render.update_region = NULL; + } gimp_projection_free_buffer (proj); @@ -512,9 +517,9 @@ gimp_projection_add_update_area (GimpProjection *proj, gint w, gint h) { - GimpArea *area; - gint off_x, off_y; - gint width, height; + cairo_rectangle_int_t rect; + gint off_x, off_y; + gint width, height; gimp_projectable_get_offset (proj->priv->projectable, &off_x, &off_y); gimp_projectable_get_size (proj->priv->projectable, &width, &height); @@ -526,13 +531,15 @@ gimp_projection_add_update_area (GimpProjection *proj, x -= off_x; y -= off_y; - area = gimp_area_new (CLAMP (x, 0, width), - CLAMP (y, 0, height), - CLAMP (x + w, 0, width), - CLAMP (y + h, 0, height)); + rect.x = CLAMP (x, 0, width); + rect.y = CLAMP (y, 0, height); + rect.width = CLAMP (x + w, 0, width) - rect.x; + rect.height = CLAMP (y + h, 0, height) - rect.y; - proj->priv->update_areas = gimp_area_list_process (proj->priv->update_areas, - area); + if (proj->priv->update_region) + cairo_region_union_rectangle (proj->priv->update_region, &rect); + else + proj->priv->update_region = cairo_region_create_rectangle (&rect); } static void @@ -540,25 +547,26 @@ gimp_projection_flush_whenever (GimpProjection *proj, gboolean now) { /* First the updates... */ - if (proj->priv->update_areas) + if (proj->priv->update_region) { if (now) /* Synchronous */ { - GSList *list; + gint n_rects = cairo_region_num_rectangles (proj->priv->update_region); + gint i; - for (list = proj->priv->update_areas; list; list = g_slist_next (list)) + for (i = 0; i < n_rects; i++) { - GimpArea *area = list->data; + cairo_rectangle_int_t rect; - if ((area->x1 != area->x2) && (area->y1 != area->y2)) - { - gimp_projection_paint_area (proj, - FALSE, /* sic! */ - area->x1, - area->y1, - (area->x2 - area->x1), - (area->y2 - area->y1)); - } + cairo_region_get_rectangle (proj->priv->update_region, + i, &rect); + + gimp_projection_paint_area (proj, + FALSE, /* sic! */ + rect.x, + rect.y, + rect.width, + rect.height); } } else /* Asynchronous */ @@ -566,9 +574,9 @@ gimp_projection_flush_whenever (GimpProjection *proj, gimp_projection_chunk_render_init (proj); } - /* Free the update lists */ - gimp_area_list_free (proj->priv->update_areas); - proj->priv->update_areas = NULL; + /* Free the update region */ + cairo_region_destroy (proj->priv->update_region); + proj->priv->update_region = NULL; } else if (! now && proj->priv->invalidate_preview) { @@ -638,20 +646,22 @@ gimp_projection_chunk_render_callback (gpointer data) static void gimp_projection_chunk_render_init (GimpProjection *proj) { - GSList *list; - /* We need to merge the ChunkRender's and the GimpProjection's - * update_areas list to keep track of which of the updates have been - * flushed and hence need to be drawn. + * update_regions list to keep track of which of the updates have + * been flushed and hence need to be drawn. */ - for (list = proj->priv->update_areas; list; list = g_slist_next (list)) + if (proj->priv->update_region) { - GimpArea *area = list->data; - - proj->priv->chunk_render.update_areas = - gimp_area_list_process (proj->priv->chunk_render.update_areas, - gimp_area_new (area->x1, area->y1, - area->x2, area->y2)); + if (proj->priv->chunk_render.update_region) + { + cairo_region_union (proj->priv->chunk_render.update_region, + proj->priv->update_region); + } + else + { + proj->priv->chunk_render.update_region = + cairo_region_copy (proj->priv->update_region); + } } /* If a chunk renderer was already running, merge the remainder of @@ -660,24 +670,25 @@ gimp_projection_chunk_render_init (GimpProjection *proj) */ if (proj->priv->chunk_render.running) { - GimpArea *area = - gimp_area_new (proj->priv->chunk_render.base_x, - proj->priv->chunk_render.y, - proj->priv->chunk_render.base_x + proj->priv->chunk_render.width, - proj->priv->chunk_render.y + (proj->priv->chunk_render.height - - (proj->priv->chunk_render.y - - proj->priv->chunk_render.base_y))); + cairo_rectangle_int_t rect; - proj->priv->chunk_render.update_areas = - gimp_area_list_process (proj->priv->chunk_render.update_areas, area); + rect.x = proj->priv->chunk_render.base_x; + rect.y = proj->priv->chunk_render.y; + rect.width = proj->priv->chunk_render.width; + rect.height = (proj->priv->chunk_render.height - + (proj->priv->chunk_render.y - + proj->priv->chunk_render.base_y)); + + cairo_region_union_rectangle (proj->priv->chunk_render.update_region, + &rect); gimp_projection_chunk_render_next_area (proj); } else { - if (proj->priv->chunk_render.update_areas == NULL) + if (proj->priv->chunk_render.update_region == NULL) { - g_warning ("%s: wanted to start chunk render with no update_areas", + g_warning ("%s: wanted to start chunk render with no update_region", G_STRFUNC); return; } @@ -702,14 +713,18 @@ gimp_projection_chunk_render_iteration (GimpProjection *proj) gint workw = GIMP_PROJECTION_CHUNK_WIDTH; gint workh = GIMP_PROJECTION_CHUNK_HEIGHT; - if (workx + workw > proj->priv->chunk_render.base_x + proj->priv->chunk_render.width) + if (workx + workw > + proj->priv->chunk_render.base_x + proj->priv->chunk_render.width) { - workw = proj->priv->chunk_render.base_x + proj->priv->chunk_render.width - workx; + workw = (proj->priv->chunk_render.base_x + + proj->priv->chunk_render.width - workx); } - if (worky + workh > proj->priv->chunk_render.base_y + proj->priv->chunk_render.height) + if (worky + workh > + proj->priv->chunk_render.base_y + proj->priv->chunk_render.height) { - workh = proj->priv->chunk_render.base_y + proj->priv->chunk_render.height - worky; + workh = (proj->priv->chunk_render.base_y + + proj->priv->chunk_render.height - worky); } gimp_projection_paint_area (proj, TRUE /* sic! */, @@ -751,22 +766,34 @@ gimp_projection_chunk_render_iteration (GimpProjection *proj) static gboolean gimp_projection_chunk_render_next_area (GimpProjection *proj) { - GimpArea *area; + cairo_rectangle_int_t rect; - if (! proj->priv->chunk_render.update_areas) + if (! proj->priv->chunk_render.update_region) return FALSE; - area = proj->priv->chunk_render.update_areas->data; + if (cairo_region_is_empty (proj->priv->chunk_render.update_region)) + { + cairo_region_destroy (proj->priv->chunk_render.update_region); + proj->priv->chunk_render.update_region = NULL; - proj->priv->chunk_render.update_areas = - g_slist_remove (proj->priv->chunk_render.update_areas, area); + return FALSE; + } - proj->priv->chunk_render.x = proj->priv->chunk_render.base_x = area->x1; - proj->priv->chunk_render.y = proj->priv->chunk_render.base_y = area->y1; - proj->priv->chunk_render.width = area->x2 - area->x1; - proj->priv->chunk_render.height = area->y2 - area->y1; + cairo_region_get_rectangle (proj->priv->chunk_render.update_region, + 0, &rect); + cairo_region_subtract_rectangle (proj->priv->chunk_render.update_region, + &rect); - gimp_area_free (area); + if (cairo_region_is_empty (proj->priv->chunk_render.update_region)) + { + cairo_region_destroy (proj->priv->chunk_render.update_region); + proj->priv->chunk_render.update_region = NULL; + } + + proj->priv->chunk_render.x = proj->priv->chunk_render.base_x = rect.x; + proj->priv->chunk_render.y = proj->priv->chunk_render.base_y = rect.y; + proj->priv->chunk_render.width = rect.width; + proj->priv->chunk_render.height = rect.height; return TRUE; } @@ -854,8 +881,11 @@ gimp_projection_projectable_changed (GimpProjectable *projectable, if (proj->priv->chunk_render.running) gimp_projection_chunk_render_stop (proj); - gimp_area_list_free (proj->priv->update_areas); - proj->priv->update_areas = NULL; + if (proj->priv->update_region) + { + cairo_region_destroy (proj->priv->update_region); + proj->priv->update_region = NULL; + } gimp_projection_free_buffer (proj); diff --git a/app/display/gimpdisplay.c b/app/display/gimpdisplay.c index 06b8abe869..f7d22b8566 100644 --- a/app/display/gimpdisplay.c +++ b/app/display/gimpdisplay.c @@ -28,7 +28,6 @@ #include "config/gimpguiconfig.h" #include "core/gimp.h" -#include "core/gimparea.h" #include "core/gimpcontainer.h" #include "core/gimpcontext.h" #include "core/gimpimage.h" @@ -68,16 +67,16 @@ typedef struct _GimpDisplayPrivate GimpDisplayPrivate; struct _GimpDisplayPrivate { - gint ID; /* unique identifier for this display */ + gint ID; /* unique identifier for this display */ - GimpImage *image; /* pointer to the associated image */ - gint instance; /* the instance # of this display as - * taken from the image at creation */ + GimpImage *image; /* pointer to the associated image */ + gint instance; /* the instance # of this display as + * taken from the image at creation */ - GtkWidget *shell; - GSList *update_areas; + GtkWidget *shell; + cairo_region_t *update_region; - guint64 last_flush_now; + guint64 last_flush_now; }; #define GIMP_DISPLAY_GET_PRIVATE(display) \ @@ -505,10 +504,6 @@ gimp_display_delete (GimpDisplay *display) if (active_tool && active_tool->focus_display == display) tool_manager_focus_display_active (display->gimp, NULL); - /* free the update area lists */ - gimp_area_list_free (private->update_areas); - private->update_areas = NULL; - if (private->shell) { GimpDisplayShell *shell = gimp_display_get_shell (display); @@ -657,6 +652,12 @@ gimp_display_set_image (GimpDisplay *display, gimp_display_disconnect (display); + if (private->update_region) + { + cairo_region_destroy (private->update_region); + private->update_region = NULL; + } + gimp_image_dec_display_count (private->image); /* set private->image before unrefing because there may be code @@ -789,17 +790,22 @@ gimp_display_update_area (GimpDisplay *display, } else { - GimpArea *area; - gint image_width = gimp_image_get_width (private->image); - gint image_height = gimp_image_get_height (private->image); + cairo_rectangle_int_t rect; + gint image_width; + gint image_height; - area = gimp_area_new (CLAMP (x, 0, image_width), - CLAMP (y, 0, image_height), - CLAMP (x + w, 0, image_width), - CLAMP (y + h, 0, image_height)); + image_width = gimp_image_get_width (private->image); + image_height = gimp_image_get_height (private->image); - private->update_areas = gimp_area_list_process (private->update_areas, - area); + rect.x = CLAMP (x, 0, image_width); + rect.y = CLAMP (y, 0, image_height); + rect.width = CLAMP (x + w, 0, image_width) - rect.x; + rect.height = CLAMP (y + h, 0, image_height) - rect.y; + + if (private->update_region) + cairo_region_union_rectangle (private->update_region, &rect); + else + private->update_region = cairo_region_create_rectangle (&rect); } } @@ -828,26 +834,27 @@ gimp_display_flush_whenever (GimpDisplay *display, { GimpDisplayPrivate *private = GIMP_DISPLAY_GET_PRIVATE (display); - if (private->update_areas) + if (private->update_region) { - GSList *list; + gint n_rects = cairo_region_num_rectangles (private->update_region); + gint i; - for (list = private->update_areas; list; list = g_slist_next (list)) + for (i = 0; i < n_rects; i++) { - GimpArea *area = list->data; + cairo_rectangle_int_t rect; - if ((area->x1 != area->x2) && (area->y1 != area->y2)) - { - gimp_display_paint_area (display, - area->x1, - area->y1, - (area->x2 - area->x1), - (area->y2 - area->y1)); - } + cairo_region_get_rectangle (private->update_region, + i, &rect); + + gimp_display_paint_area (display, + rect.x, + rect.y, + rect.width, + rect.height); } - gimp_area_list_free (private->update_areas); - private->update_areas = NULL; + cairo_region_destroy (private->update_region); + private->update_region = NULL; } if (now)