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:
@@ -177,6 +177,7 @@ Scale_ExpandRect (SDL_Rect* rect, int expansion, SDL_Rect* limits)
|
|||||||
typedef struct _BLEND_PARAMS
|
typedef struct _BLEND_PARAMS
|
||||||
{
|
{
|
||||||
int shift_bits;
|
int shift_bits;
|
||||||
|
int pre_shift;
|
||||||
Uint32 low_mask;
|
Uint32 low_mask;
|
||||||
Uint32 high_mask;
|
Uint32 high_mask;
|
||||||
} BLEND_PARAMS;
|
} BLEND_PARAMS;
|
||||||
@@ -185,7 +186,11 @@ typedef struct _BLEND_PARAMS
|
|||||||
__inline__ Uint32
|
__inline__ Uint32
|
||||||
Scale_BlendPixels_2 (BLEND_PARAMS bp, Uint32 pix1, Uint32 pix2)
|
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);
|
((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,
|
Scale_BlendPixels_4 (BLEND_PARAMS bp, Uint32 pix1, Uint32 pix2,
|
||||||
Uint32 pix3, Uint32 pix4)
|
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)
|
(pix3 & bp.low_mask) + (pix4 & bp.low_mask)
|
||||||
) >> 2) & bp.low_mask) +
|
) >> 2) & bp.low_mask) +
|
||||||
|
*/
|
||||||
((pix1 & bp.high_mask) >> 2) + ((pix2 & bp.high_mask) >> 2) +
|
((pix1 & bp.high_mask) >> 2) + ((pix2 & bp.high_mask) >> 2) +
|
||||||
((pix3 & bp.high_mask) >> 2) + ((pix4 & 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;
|
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
|
// compare pixels by their RGB
|
||||||
__inline__ int
|
__inline__ int
|
||||||
Scale_GetRGBDelta (SDL_PixelFormat* fmt, Uint32 pix1, Uint32 pix2)
|
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
|
// bilinear scaling to 2x
|
||||||
void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
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;
|
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;
|
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?
|
// 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)
|
switch (dst->format->BytesPerPixel)
|
||||||
{
|
{
|
||||||
case 2:
|
case 2:
|
||||||
@@ -2418,7 +2516,11 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
Uint16 *dst_p = (Uint16 *) dst->pixels;
|
Uint16 *dst_p = (Uint16 *) dst->pixels;
|
||||||
Uint32 p[4];
|
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;
|
src_p2 = src_p;
|
||||||
j = i;
|
j = i;
|
||||||
@@ -2429,7 +2531,7 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
else
|
else
|
||||||
p[2] = 0;
|
p[2] = 0;
|
||||||
|
|
||||||
for (x = 0; x < w; ++x)
|
for (x = drx; x < xend; ++x, ++dst_p)
|
||||||
{
|
{
|
||||||
if (j == i)
|
if (j == i)
|
||||||
{
|
{
|
||||||
@@ -2456,24 +2558,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fa = bilinear_table[j][0];
|
*dst_p = Scale_BlendPixels_bilinear (
|
||||||
fb = bilinear_table[j][1];
|
blend16, p, bilinear_table[j]
|
||||||
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);
|
|
||||||
|
|
||||||
if (j & 2)
|
if (j & 2)
|
||||||
{
|
{
|
||||||
@@ -2490,6 +2577,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
|
|
||||||
if (!i)
|
if (!i)
|
||||||
src_p = src_p2;
|
src_p = src_p2;
|
||||||
|
else
|
||||||
|
src_p += dsrc;
|
||||||
|
|
||||||
i = !i;
|
i = !i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2497,9 +2587,77 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
}
|
}
|
||||||
case 3:
|
case 3:
|
||||||
{
|
{
|
||||||
// 24bpp mode bilinear scaling isn't implemented currently
|
PIXEL_24BIT *src_p = (PIXEL_24BIT *) src->pixels, *src_p2;
|
||||||
// it would probably be too slow to be useful anyway
|
PIXEL_24BIT *dst_p = (PIXEL_24BIT *) dst->pixels;
|
||||||
Scale_Nearest (src, dst, r);
|
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;
|
break;
|
||||||
}
|
}
|
||||||
case 4:
|
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 *dst_p = (Uint32 *) dst->pixels;
|
||||||
Uint32 p[4];
|
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;
|
src_p2 = src_p;
|
||||||
j = i;
|
j = i;
|
||||||
@@ -2519,7 +2681,7 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
else
|
else
|
||||||
p[2] = 0;
|
p[2] = 0;
|
||||||
|
|
||||||
for (x = 0; x < w; ++x)
|
for (x = drx; x < xend; ++x, ++dst_p)
|
||||||
{
|
{
|
||||||
if (j == i)
|
if (j == i)
|
||||||
{
|
{
|
||||||
@@ -2546,25 +2708,10 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fa = bilinear_table[j][0];
|
*dst_p = Scale_BlendPixels_bilinear (
|
||||||
fb = bilinear_table[j][1];
|
blend16, p, bilinear_table[j]
|
||||||
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);
|
|
||||||
|
|
||||||
if (j & 2)
|
if (j & 2)
|
||||||
{
|
{
|
||||||
j = i;
|
j = i;
|
||||||
@@ -2580,6 +2727,9 @@ void Scale_BilinearFilter (SDL_Surface *src, SDL_Surface *dst, SDL_Rect *r)
|
|||||||
|
|
||||||
if (!i)
|
if (!i)
|
||||||
src_p = src_p2;
|
src_p = src_p2;
|
||||||
|
else
|
||||||
|
src_p += dsrc;
|
||||||
|
|
||||||
i = !i;
|
i = !i;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user