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.
This commit is contained in:
Michael Natterer 2014-05-31 01:22:54 +02:00
parent 6845766200
commit 9b341d05bb
6 changed files with 149 additions and 262 deletions

View File

@ -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 \

View File

@ -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;

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#include "config.h"
#include <glib-object.h>
#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);
}

View File

@ -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 <http://www.gnu.org/licenses/>.
*/
#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__ */

View File

@ -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);

View File

@ -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)