app: in GimpProjection, fix reinit. of current row when chunk height changes

In GimpProjection's chunk renderer, when the chunk height changes
in the middle of a row, we need to merge the remainder of the
current render area back into the renderer's update region, and
refetch the remainder of the row as the new render area, so that we
don't miss any unrendered area, or re-render already-rendered area,
due to the change in chunk height.  However, we should previously
fail to verify that the fetched area is, in fact, the remainder of
the current row, which could cause us to render the wrong area,
missing parts of the update region.

Fix this, by breaking up some of the chunk-renderer fucntions into
smaller sub-functions, and using those in order to explicitly set
the new render area to the remainder of the current row when the
chunk height changes.  This also avoids erroneously merging the
unflushed update region of the projection into the renderer's
update region.
This commit is contained in:
Ell 2018-12-06 08:44:23 -05:00
parent 411ddb7e48
commit c9c2397b0d
1 changed files with 87 additions and 45 deletions

View File

@ -186,11 +186,16 @@ static void gimp_projection_chunk_render_start (GimpProjection *proj)
static void gimp_projection_chunk_render_stop (GimpProjection *proj);
static gboolean gimp_projection_chunk_render_callback (gpointer data);
static void gimp_projection_chunk_render_init (GimpProjection *proj);
static void gimp_projection_chunk_render_reinit (GimpProjection *proj,
gboolean assume_running);
static void gimp_projection_chunk_render_reinit (GimpProjection *proj);
static void gimp_projection_chunk_render_merge (GimpProjection *proj);
static gboolean gimp_projection_chunk_render_iteration(GimpProjection *proj,
gboolean chunk);
static gboolean gimp_projection_chunk_render_next_area(GimpProjection *proj);
static void gimp_projection_chunk_render_set_area (GimpProjection *proj,
gint x,
gint y,
gint w,
gint h);
static void gimp_projection_paint_area (GimpProjection *proj,
gboolean now,
gint x,
@ -615,7 +620,7 @@ gimp_projection_set_priority_rect (GimpProjection *proj,
proj->priv->priority_rect = rect;
if (proj->priv->chunk_render.idle_id)
gimp_projection_chunk_render_reinit (proj, FALSE);
gimp_projection_chunk_render_reinit (proj);
}
}
@ -909,12 +914,11 @@ gimp_projection_chunk_render_init (GimpProjection *proj)
chunk_render->target_n_pixels = GIMP_PROJECTION_CHUNK_WIDTH *
GIMP_PROJECTION_CHUNK_HEIGHT;
gimp_projection_chunk_render_reinit (proj, FALSE);
gimp_projection_chunk_render_reinit (proj);
}
static void
gimp_projection_chunk_render_reinit (GimpProjection *proj,
gboolean assume_running)
gimp_projection_chunk_render_reinit (GimpProjection *proj)
{
GimpProjectionChunkRender *chunk_render = &proj->priv->chunk_render;
@ -940,8 +944,34 @@ gimp_projection_chunk_render_reinit (GimpProjection *proj,
* its unrendered area with the update_areas list, and make it start
* work on the next unrendered area in the list.
*/
if (chunk_render->idle_id || assume_running)
if (chunk_render->idle_id)
{
gimp_projection_chunk_render_merge (proj);
gimp_projection_chunk_render_next_area (proj);
}
else
{
if (chunk_render->update_region == NULL)
{
g_warning ("%s: wanted to start chunk render with no update_region",
G_STRFUNC);
return;
}
proj->priv->chunk_render.target_n_pixels = GIMP_PROJECTION_CHUNK_WIDTH *
GIMP_PROJECTION_CHUNK_HEIGHT;
gimp_projection_chunk_render_next_area (proj);
gimp_projection_chunk_render_start (proj);
}
}
static void
gimp_projection_chunk_render_merge (GimpProjection *proj)
{
GimpProjectionChunkRender *chunk_render = &proj->priv->chunk_render;
cairo_rectangle_int_t rect;
gint work_h = 0;
@ -972,25 +1002,6 @@ gimp_projection_chunk_render_reinit (GimpProjection *proj,
cairo_region_union_rectangle (chunk_render->update_region, &rect);
else
chunk_render->update_region = cairo_region_create_rectangle (&rect);
gimp_projection_chunk_render_next_area (proj);
}
else
{
if (chunk_render->update_region == NULL)
{
g_warning ("%s: wanted to start chunk render with no update_region",
G_STRFUNC);
return;
}
proj->priv->chunk_render.target_n_pixels = GIMP_PROJECTION_CHUNK_WIDTH *
GIMP_PROJECTION_CHUNK_HEIGHT;
gimp_projection_chunk_render_next_area (proj);
gimp_projection_chunk_render_start (proj);
}
}
/* Unless specified otherwise, projection re-rendering is organised by
@ -1044,11 +1055,21 @@ gimp_projection_chunk_render_iteration (GimpProjection *proj,
if (work_h != chunk_render->work_height)
{
/* if the chunk height changed in the middle of a row, refetch the
* current area, so that we're back at the beginning of a row
/* if the chunk height changed in the middle of a row, merge the
* remaining area back into the update region, and reset the current area
* to the remainder of the row, using the new chunk height
*/
if (work_x != chunk_render->x)
gimp_projection_chunk_render_reinit (proj, TRUE);
{
gimp_projection_chunk_render_merge (proj);
gimp_projection_chunk_render_set_area (
proj,
work_x,
work_y,
chunk_render->x + chunk_render->width - work_x,
work_h);
}
chunk_render->work_height = work_h;
}
@ -1117,10 +1138,33 @@ gimp_projection_chunk_render_next_area (GimpProjection *proj)
cairo_region_destroy (next_region);
gimp_projection_chunk_render_set_area (proj,
rect.x, rect.y,
rect.width, rect.height);
return TRUE;
}
static void
gimp_projection_chunk_render_set_area (GimpProjection *proj,
gint x,
gint y,
gint w,
gint h)
{
GimpProjectionChunkRender *chunk_render = &proj->priv->chunk_render;
cairo_rectangle_int_t rect;
rect.x = x;
rect.y = y;
rect.width = w;
rect.height = h;
if (chunk_render->update_region)
{
cairo_region_subtract_rectangle (chunk_render->update_region, &rect);
if (cairo_region_is_empty (chunk_render->update_region))
{
g_clear_pointer (&chunk_render->update_region, cairo_region_destroy);
}
@ -1131,8 +1175,6 @@ gimp_projection_chunk_render_next_area (GimpProjection *proj)
chunk_render->work_x = chunk_render->x;
chunk_render->work_y = chunk_render->y;
return TRUE;
}
static void