a small optimization for the vertical gradients, and use the same log(n) strategy to use less memcpy's for filling out the horizontal gradients

This commit is contained in:
Dana Jansens 2008-02-10 18:08:05 -05:00 committed by Mikael Magnusson
parent 3611c8210c
commit 9c72998684
2 changed files with 73 additions and 20 deletions

View file

@ -218,8 +218,8 @@ static inline void repeat_pixel(RrPixel32 *start, gint w)
/* for >= 8, then use O(log n) memcpy's... */ /* for >= 8, then use O(log n) memcpy's... */
else { else {
gint len = 4; gchar *cdest;
gint lenbytes = 4 * sizeof(RrPixel32); gint lenbytes;
/* copy the first 3 * 32 bits (3 words) ourselves - then we have /* copy the first 3 * 32 bits (3 words) ourselves - then we have
3 + the original 1 = 4 words to make copies of at a time 3 + the original 1 = 4 words to make copies of at a time
@ -229,16 +229,38 @@ static inline void repeat_pixel(RrPixel32 *start, gint w)
for (x = 3; x > 0; --x) for (x = 3; x > 0; --x)
*(dest++) = *start; *(dest++) = *start;
for (x = w - 4; x > 0;) { /* cdest is a pointer to the pixel data that is typed char* so that
memcpy(dest, start, lenbytes); adding 1 to its position moves it only one byte
x -= len;
dest += len; lenbytes is the amount of bytes that we will be copying each
len <<= 1; iteration. this doubles each time through the loop.
x is the number of bytes left to copy into. lenbytes will alwaysa
be bounded by x
this loop will run O(log n) times (n is the number of bytes we
need to copy into), since the size of the copy is doubled each
iteration. it seems that gcc does some nice optimizations to make
this memcpy very fast on hardware with support for vector operations
such as mmx or see. here is an idea of the kind of speed up we are
getting by doing this (splitvertical3 switches from doing
"*(data++) = color" n times to doing this memcpy thing log n times:
% cumulative self self total
time seconds seconds calls ms/call ms/call name
49.44 0.88 0.88 1063 0.83 0.83 splitvertical1
47.19 1.72 0.84 1063 0.79 0.79 splitvertical2
2.81 1.77 0.05 1063 0.05 0.05 splitvertical3
*/
cdest = (gchar*)dest;
lenbytes = 4 * sizeof(RrPixel32);
for (x = (w - 4) * sizeof(RrPixel32); x > 0;) {
memcpy(cdest, start, lenbytes);
x -= lenbytes;
cdest += lenbytes;
lenbytes <<= 1; lenbytes <<= 1;
if (len > x) { if (lenbytes > x)
len = x; lenbytes = x;
lenbytes = x * sizeof(RrPixel32);
}
} }
} }
} }
@ -534,12 +556,14 @@ static void gradient_splitvertical(RrAppearance *a, gint w, gint h)
static void gradient_horizontal(RrSurface *sf, gint w, gint h) static void gradient_horizontal(RrSurface *sf, gint w, gint h)
{ {
gint x, y; gint x, y, cpbytes;
RrPixel32 *data = sf->pixel_data, *datav; RrPixel32 *data = sf->pixel_data, *datav;
gchar *datac;
VARS(x); VARS(x);
SETUP(x, sf->primary, sf->secondary, w); SETUP(x, sf->primary, sf->secondary, w);
/* set the color values for the first row */
datav = data; datav = data;
for (x = w - 1; x > 0; --x) { /* 0 -> w - 1 */ for (x = w - 1; x > 0; --x) { /* 0 -> w - 1 */
*datav = COLOR(x); *datav = COLOR(x);
@ -549,22 +573,32 @@ static void gradient_horizontal(RrSurface *sf, gint w, gint h)
*datav = COLOR(x); *datav = COLOR(x);
++datav; ++datav;
for (y = h - 1; y > 0; --y) { /* 1 -> h */ /* copy the first row to the rest in O(logn) copies */
memcpy(datav, data, w * sizeof(RrPixel32)); datac = (gchar*)datav;
datav += w; cpbytes = 1 * w * sizeof(RrPixel32);
for (y = (h - 1) * w * sizeof(RrPixel32); y > 0;) {
memcpy(datac, data, cpbytes);
y -= cpbytes;
datac += cpbytes;
cpbytes <<= 1;
if (cpbytes > y)
cpbytes = y;
} }
} }
static void gradient_mirrorhorizontal(RrSurface *sf, gint w, gint h) static void gradient_mirrorhorizontal(RrSurface *sf, gint w, gint h)
{ {
gint x, y, half1, half2; gint x, y, half1, half2, cpbytes;
RrPixel32 *data = sf->pixel_data, *datav; RrPixel32 *data = sf->pixel_data, *datav;
gchar *datac;
VARS(x); VARS(x);
half1 = (w + 1) / 2; half1 = (w + 1) / 2;
half2 = w / 2; half2 = w / 2;
/* set the color values for the first row */
SETUP(x, sf->primary, sf->secondary, half1); SETUP(x, sf->primary, sf->secondary, half1);
datav = data; datav = data;
for (x = half1 - 1; x > 0; --x) { /* 0 -> half1 - 1 */ for (x = half1 - 1; x > 0; --x) { /* 0 -> half1 - 1 */
@ -586,9 +620,16 @@ static void gradient_mirrorhorizontal(RrSurface *sf, gint w, gint h)
++datav; ++datav;
} }
for (y = h - 1; y > 0; --y) { /* 1 -> h */ /* copy the first row to the rest in O(logn) copies */
memcpy(datav, data, w * sizeof(RrPixel32)); datac = (gchar*)datav;
datav += w; cpbytes = 1 * w * sizeof(RrPixel32);
for (y = (h - 1) * w * sizeof(RrPixel32); y > 0;) {
memcpy(datac, data, cpbytes);
y -= cpbytes;
datac += cpbytes;
cpbytes <<= 1;
if (cpbytes > y)
cpbytes = y;
} }
} }

View file

@ -68,7 +68,7 @@ gint main()
inst = RrInstanceNew(ob_display, ob_screen); inst = RrInstanceNew(ob_display, ob_screen);
look = RrAppearanceNew(inst, 0); look = RrAppearanceNew(inst, 0);
look->surface.grad = RR_SURFACE_SPLIT_VERTICAL; look->surface.grad = RR_SURFACE_MIRROR_HORIZONTAL;
look->surface.secondary = RrColorParse(inst, "Yellow"); look->surface.secondary = RrColorParse(inst, "Yellow");
look->surface.split_secondary = RrColorParse(inst, "Red"); look->surface.split_secondary = RrColorParse(inst, "Red");
look->surface.split_primary = RrColorParse(inst, "Green"); look->surface.split_primary = RrColorParse(inst, "Green");
@ -79,6 +79,18 @@ gint main()
return 0; return 0;
} }
#if BIGTEST
int i;
look->surface.pixel_data = g_new(RrPixel32, w*h);
for (i = 0; i < 10000; ++i) {
printf("\r%d", i);
fflush(stdout);
RrRender(look, w, h);
}
exit (0);
#endif
RrPaint(look, win, w, h); RrPaint(look, win, w, h);
done = 0; done = 0;
while (!done) { while (!done) {