Serialize access to source and destination memory to reduce the chance of

2003-04-29  Pedro Gimeno  <pggimeno@wanadoo.es>

	* app/paint-funcs/paint-funcs.c (shrink_line): Serialize access to
	source and destination memory to reduce the chance of cache misses
	when dealing with large images. Enable some assertions temporarily
	to ensure that the algorithm works properly before backporting it.
This commit is contained in:
Pedro Gimeno 2003-04-29 15:50:39 +00:00 committed by Pedro Gimeno Fortea
parent 0e4c3b03bc
commit 06a65279ae
2 changed files with 76 additions and 47 deletions

View file

@ -1,3 +1,10 @@
2003-04-29 Pedro Gimeno <pggimeno@wanadoo.es>
* app/paint-funcs/paint-funcs.c (shrink_line): Serialize access to
source and destination memory to reduce the chance of cache misses
when dealing with large images. Enable some assertions temporarily
to ensure that the algorithm works properly before backporting it.
2003-04-28 Michael Natterer <mitch@gimp.org>
* plug-ins/common/jpeg.c: default to not showing the in-display
@ -14,8 +21,8 @@
* app/paint-funcs/paint-funcs.c: Some reformattings to improve
readability.
(shrink_line): Added some explanatory comments.
(border_region): Fixed wrong (though harmless) allocation bug: used
sizeof(gint16 *) where sizeof(gint16) was needed.
(border_region): Fixed wrong (though harmless) allocation bug:
used sizeof(gint16 *) where sizeof(gint16) was needed.
2003-04-23 Sven Neumann <sven@gimp.org>

View file

@ -2716,7 +2716,7 @@ scale_region_no_resample (PixelRegion *srcPR,
y_src_offsets = g_new (gint, height);
src = g_new (guchar, orig_width * bytes);
dest = g_new (guchar, width * bytes);
/* pre-calc the scale tables */
for (b = 0; b < bytes; b++)
for (x = 0; x < width; x++)
@ -2746,7 +2746,7 @@ scale_region_no_resample (PixelRegion *srcPR,
pixel_region_set_row (destPR, 0, y, width, dest);
}
g_free (x_src_offsets);
g_free (y_src_offsets);
g_free (src);
@ -2868,10 +2868,11 @@ shrink_line (gdouble *dest,
gint b;
gdouble *srcp;
gdouble *destp;
gdouble accum;
gdouble accum[4];
gdouble slice;
const gdouble avg_ratio = (gdouble) width / old_width;
gint srcpos;
const gdouble inv_width = 1.0 / width;
gint slicepos; /* slice position relative to width */
#if 0
g_printerr ("shrink_line bytes=%d old_width=%d width=%d interp=%d "
@ -2879,55 +2880,76 @@ shrink_line (gdouble *dest,
bytes, old_width, width, interp, avg_ratio);
#endif
g_return_if_fail (bytes <= 4);
/* This algorithm calculates the weighted average of pixel data that
each output pixel must receive, taking into account that it always
scales down, i.e. there's always more than one input pixel per each
output pixel. */
srcp = src;
destp = dest;
slicepos = 0;
/* Initialize accum to the first pixel slice. As there is no partial
pixel at start, that value is 0. The source data is interleaved, so
we maintain BYTES accumulators at the same time to deal with that
many channels simultaneously. */
for (b = 0; b < bytes; b++)
accum[b] = 0.0;
for (x = 0; x < width; x++)
{
/* This algorithm calculates the weighted average of pixel data that
each output pixel must receive, taking into account that it always
scales down, i.e. there's always more than one input pixel per each
output pixel.
*/
srcp = &src[b];
destp = &dest[b];
srcpos = 0;
/* Initialize accum to the first pixel slice. As there is no partial
pixel at start, that value is 0. */
accum = 0.0;
for (x = 0; x < width; x++)
/* Accumulate whole pixels. */
do
{
/* Accumulate whole pixels. */
while (srcpos < old_width)
{
accum += *srcp;
srcp += bytes;
for (b = 0; b < bytes; b++)
accum[b] += *srcp++;
srcpos += width;
}
srcpos -= old_width;
/* We've accumulated a whole pixel where just a slice of it was
needed. Subtract it now. */
slice = (srcpos == 0) ? 0.0 : (srcp[-bytes] * srcpos) / width;
accum -= slice;
*destp = accum * avg_ratio;
destp += bytes;
/* That slice is the initial value for the next round. */
accum = slice;
slicepos += width;
}
while (slicepos < old_width);
slicepos -= old_width;
#if 0
/* Sanity check: srcp should point to the next-to-last position. */
if (!(srcp - src - b == old_width * bytes))
g_warning ("Assertion (srcp - src - b == old_width * bytes) failed.");
#endif
if (! (slicepos < width))
g_warning ("Assertion (slicepos < width) failed. Please report.");
if (slicepos == 0)
{
/* Simplest case: we have reached a whole pixel boundary. Store
the average value per channel and reset the accumulators for
the next round.
The main reason to treat this case separately is to avoid an
access to out-of-bounds memory for the first pixel. */
for (b = 0; b < bytes; b++)
{
*destp++ = accum[b] * avg_ratio;
accum[b] = 0.0;
}
}
else
{
for (b = 0; b < bytes; b++)
{
/* We have accumulated a whole pixel per channel where just a
slice of it was needed. Subtract now the previous pixel's
extra slice. */
slice = srcp[- bytes + b] * slicepos * inv_width;
*destp++ = (accum[b] - slice) * avg_ratio;
/* That slice is the initial value for the next round. */
accum[b] = slice;
}
}
}
/* Sanity check: srcp should point to the next-to-last position, and
slicepos should be zero. */
if (! (srcp - src == old_width * bytes && slicepos == 0))
g_warning ("Assertion (srcp - src == old_width * bytes && slicepos == 0)"
" failed. Please report.");
}
static void