2nd phase scaling optimizations; bilinear: improved blend, added 24bpp, added region updates; biadapt: lower bits ignored in blends

git-svn-id: svn://svn.code.sf.net/p/sc2/code/trunk@1061 8092fc87-c524-0410-9efc-e669fe64eaf9
This commit is contained in:
avolkov
2003-07-18 03:52:00 +00:00
parent 37f326571a
commit 0dfff91915
+202 -52
View File
@@ -177,6 +177,7 @@ Scale_ExpandRect (SDL_Rect* rect, int expansion, SDL_Rect* limits)
typedef struct _BLEND_PARAMS
{
int shift_bits;
int pre_shift;
Uint32 low_mask;
Uint32 high_mask;
} BLEND_PARAMS;
@@ -185,7 +186,11 @@ typedef struct _BLEND_PARAMS
__inline__ Uint32
Scale_BlendPixels_2 (BLEND_PARAMS bp, Uint32 pix1, Uint32 pix2)
{
return (pix1 & pix2 & bp.low_mask) +
return
/* lower bits can be safely ignored - the error is minimal
expression that calcs them is left for posterity
(pix1 & pix2 & bp.low_mask) +
*/
((pix1 & bp.high_mask) >> 1) + ((pix2 & bp.high_mask) >> 1);
}
@@ -194,9 +199,13 @@ __inline__ Uint32
Scale_BlendPixels_4 (BLEND_PARAMS bp, Uint32 pix1, Uint32 pix2,
Uint32 pix3, Uint32 pix4)
{
return ((((pix1 & bp.low_mask) + (pix2 & bp.low_mask) +
return
/* lower bits can be safely ignored - the error is minimal
expression that calcs them is left for posterity
((((pix1 & bp.low_mask) + (pix2 & bp.low_mask) +
(pix3 & bp.low_mask) + (pix4 & bp.low_mask)
) >> 2) & bp.low_mask) +
*/
((pix1 & bp.high_mask) >> 2) + ((pix2 & bp.high_mask) >> 2) +
((pix3 & bp.high_mask) >> 2) + ((pix4 & bp.high_mask) >> 2);
}
@@ -222,6 +231,43 @@ Scale_CalcBlendMasks (SDL_PixelFormat* fmt, unsigned int npixels,
pbp->high_mask = (fmt->Rmask | fmt->Gmask | fmt->Bmask) ^ pbp->low_mask;
}
// compute channel masks for N-pixel blending
// N must be a power of 2 and generally should not be more than 2^(B/2),
// where B is the number of bits/channel
// although, blending weights may dictate other conditions
__inline__ void
Scale_CalcChannelMasks (SDL_PixelFormat* fmt, unsigned int npixels,
BLEND_PARAMS* pbp)
{
Uint32 masks[3] = {fmt->Rmask, fmt->Gmask, fmt->Bmask};
int i, swapped = 1;
// this just does an integer log-base-2(npixels)
for (pbp->shift_bits = 0, npixels >>= 1; npixels != 0; npixels >>= 1)
pbp->shift_bits++;
// buble-sort masks
while (swapped)
{
swapped = 0;
for (i = 0; i < 2; ++i)
{
if (masks[i] < masks[i + 1])
{
Uint32 tval = masks[i];
masks[i] = masks[i + 1];
masks[i + 1] = tval;
swapped++;
}
}
}
pbp->high_mask = masks[0] | masks[2];
pbp->low_mask = masks[1];
pbp->pre_shift = pbp->high_mask >= (Uint32)1 << (32 - pbp->shift_bits);
}
// compare pixels by their RGB
__inline__ int
Scale_GetRGBDelta (SDL_PixelFormat* fmt, Uint32 pix1, Uint32 pix2)
@@ -2395,21 +2441,73 @@ void Scale_Nearest (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
}
}
// bilinear weighted blend of four pixels
__inline__ Uint32
Scale_BlendPixels_bilinear (BLEND_PARAMS bp, Uint32* p, const Uint32* w)
{
if (bp.pre_shift)
{ // high pre-shifted version
return (((((p[0] & bp.high_mask) >> 4) * w[0]) +
(((p[1] & bp.high_mask) >> 4) * w[1]) +
(((p[2] & bp.high_mask) >> 4) * w[2]) +
(((p[3] & bp.high_mask) >> 4) * w[3]))
& bp.high_mask) |
(((((p[0] & bp.low_mask) * w[0]) +
((p[1] & bp.low_mask) * w[1]) +
((p[2] & bp.low_mask) * w[2]) +
((p[3] & bp.low_mask) * w[3]))
>> 4) & bp.low_mask);
}
else
{ // high post-shifted version
return (((((p[0] & bp.high_mask) * w[0]) +
((p[1] & bp.high_mask) * w[1]) +
((p[2] & bp.high_mask) * w[2]) +
((p[3] & bp.high_mask) * w[3]))
>> 4) & bp.high_mask) |
(((((p[0] & bp.low_mask) * w[0]) +
((p[1] & bp.low_mask) * w[1]) +
((p[2] & bp.low_mask) * w[2]) +
((p[3] & bp.low_mask) * w[3]))
>> 4) & bp.low_mask);
}
}
// bilinear scaling to 2x
void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
{
int x, y, i = 0, j, fa, fb, fc, fd;
int x, y, i = 0, j;
const int w = dst->w, h = dst->h;
int drx, dry;
int xend, yend;
int dsrc, ddst;
SDL_Rect *region = r;
SDL_Rect limits;
SDL_PixelFormat *fmt = dst->format;
BLEND_PARAMS blend16;
// TODO: support for partial updates, expand weight matrix in the code
// expand updated region if necessary
// pixels neighbooring the updated region may
// change as a result of updates
limits.x = 0;
limits.y = 0;
limits.w = src->w;
limits.h = src->h;
Scale_ExpandRect (region, 1, &limits);
drx = 2 * region->x;
dry = 2 * region->y;
xend = 2 * (region->x + region->w);
yend = 2 * (region->y + region->h);
dsrc = src->w - region->w;
ddst = dst->w - 2 * region->w;
// precompute the blending masks and shifts
Scale_CalcChannelMasks (fmt, 16, &blend16);
// TODO: expand weight matrix in the code
// so that compiler can optimize the mults?
r->x = 0;
r->y = 0;
r->w = src->w;
r->h = src->h;
switch (dst->format->BytesPerPixel)
{
case 2:
@@ -2418,7 +2516,11 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
Uint16 *dst_p = (Uint16 *) dst->pixels;
Uint32 p[4];
for (y = 0; y < h; ++y)
// move ptrs to the first updated pixel
src_p += src->w * region->y + region->x;
dst_p += (dst->w * region->y + region->x) * 2;
for (y = dry; y < yend; ++y, dst_p += ddst)
{
src_p2 = src_p;
j = i;
@@ -2429,7 +2531,7 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
else
p[2] = 0;
for (x = 0; x < w; ++x)
for (x = drx; x < xend; ++x, ++dst_p)
{
if (j == i)
{
@@ -2456,24 +2558,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
}
}
fa = bilinear_table[j][0];
fb = bilinear_table[j][1];
fc = bilinear_table[j][2];
fd = bilinear_table[j][3];
*dst_p++ =
(((((p[0] & fmt->Rmask) * fa) +
((p[1] & fmt->Rmask) * fb) +
((p[2] & fmt->Rmask) * fc) +
((p[3] & fmt->Rmask) * fd)) >> 4) & fmt->Rmask) |
(((((p[0] & fmt->Gmask) * fa) +
((p[1] & fmt->Gmask) * fb) +
((p[2] & fmt->Gmask) * fc) +
((p[3] & fmt->Gmask) * fd)) >> 4) & fmt->Gmask) |
(((((p[0] & fmt->Bmask) * fa) +
((p[1] & fmt->Bmask) * fb) +
((p[2] & fmt->Bmask) * fc) +
((p[3] & fmt->Bmask) * fd)) >> 4) & fmt->Bmask);
*dst_p = Scale_BlendPixels_bilinear (
blend16, p, bilinear_table[j]
);
if (j & 2)
{
@@ -2490,6 +2577,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
if (!i)
src_p = src_p2;
else
src_p += dsrc;
i = !i;
}
@@ -2497,9 +2587,77 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
}
case 3:
{
// 24bpp mode bilinear scaling isn't implemented currently
// it would probably be too slow to be useful anyway
Scale_Nearest (src, dst, r);
PIXEL_24BIT *src_p = (PIXEL_24BIT *) src->pixels, *src_p2;
PIXEL_24BIT *dst_p = (PIXEL_24BIT *) dst->pixels;
Uint32 p[4];
// move ptrs to the first updated pixel
src_p += src->w * region->y + region->x;
dst_p += (dst->w * region->y + region->x) * 2;
for (y = dry; y < yend; ++y, dst_p += ddst)
{
src_p2 = src_p;
j = i;
p[0] = GET_PIX_24BIT (src_p);
if (y < h - 2)
p[2] = GET_PIX_24BIT (src_p + src->w);
else
p[2] = 0;
for (x = drx; x < xend; ++x, ++dst_p)
{
if (j == i)
{
if (y < h - 2)
{
if (x < w - 2)
{
p[1] = GET_PIX_24BIT (src_p + 1);
p[3] = GET_PIX_24BIT (src_p + src->w + 1);
}
else
{
p[1] = 0;
p[3] = 0;
}
}
else
{
if (x < w - 2)
p[1] = GET_PIX_24BIT (src_p + 1);
else
p[1] = 0;
p[3] = 0;
}
}
SET_PIX_24BIT (dst_p, Scale_BlendPixels_bilinear (
blend16, p, bilinear_table[j]
));
if (j & 2)
{
j = i;
src_p++;
p[0] = p[1];
p[2] = p[3];
}
else
{
j = i | 2;
}
}
if (!i)
src_p = src_p2;
else
src_p += dsrc;
i = !i;
}
break;
}
case 4:
@@ -2508,7 +2666,11 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
Uint32 *dst_p = (Uint32 *) dst->pixels;
Uint32 p[4];
for (y = 0; y < h; ++y)
// move ptrs to the first updated pixel
src_p += src->w * region->y + region->x;
dst_p += (dst->w * region->y + region->x) * 2;
for (y = dry; y < yend; ++y, dst_p += ddst)
{
src_p2 = src_p;
j = i;
@@ -2519,7 +2681,7 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
else
p[2] = 0;
for (x = 0; x < w; ++x)
for (x = drx; x < xend; ++x, ++dst_p)
{
if (j == i)
{
@@ -2546,24 +2708,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
}
}
fa = bilinear_table[j][0];
fb = bilinear_table[j][1];
fc = bilinear_table[j][2];
fd = bilinear_table[j][3];
*dst_p++ =
(((((((p[0] & fmt->Rmask) >> fmt->Rshift) * fa) +
(((p[1] & fmt->Rmask) >> fmt->Rshift) * fb) +
(((p[2] & fmt->Rmask) >> fmt->Rshift) * fc) +
(((p[3] & fmt->Rmask) >> fmt->Rshift) * fd)) >> 4) << fmt->Rshift) & fmt->Rmask) |
(((((((p[0] & fmt->Gmask) >> fmt->Gshift) * fa) +
(((p[1] & fmt->Gmask) >> fmt->Gshift) * fb) +
(((p[2] & fmt->Gmask) >> fmt->Gshift) * fc) +
(((p[3] & fmt->Gmask) >> fmt->Gshift) * fd)) >> 4) << fmt->Gshift) & fmt->Gmask) |
(((((((p[0] & fmt->Bmask) >> fmt->Bshift) * fa) +
(((p[1] & fmt->Bmask) >> fmt->Bshift) * fb) +
(((p[2] & fmt->Bmask) >> fmt->Bshift) * fc) +
(((p[3] & fmt->Bmask) >> fmt->Bshift) * fd)) >> 4) << fmt->Bshift) & fmt->Bmask);
*dst_p = Scale_BlendPixels_bilinear (
blend16, p, bilinear_table[j]
);
if (j & 2)
{
@@ -2580,6 +2727,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
if (!i)
src_p = src_p2;
else
src_p += dsrc;
i = !i;
}