mirror of
https://github.com/hrydgard/ppsspp.git
synced 2026-10-26 19:58:36 +01:00
Change indentation to tabs.
This commit is contained in:
1 file changed
+221
-221
+221
-221
@@ -206,146 +206,146 @@ void mix(u32* data, u32* source, u32* mask, u32 maskmax, int width, int l, int u
|
||||
|
||||
// Loads a sample (4 bytes) from image into 'output'.
|
||||
static void load_sample(ptrdiff_t w, ptrdiff_t h, ptrdiff_t s, const u8 *pixels, int wrap_mode, ptrdiff_t x, ptrdiff_t y, u8 *output) {
|
||||
// Check if the sample is inside. NOTE: for b>=0
|
||||
// the expression (UNSIGNED)a<(UNSIGNED)b is
|
||||
// equivalent to a>=0&&a<b.
|
||||
typedef int static_assert_size_matches[sizeof(ptrdiff_t)==sizeof(size_t)?1:-1];
|
||||
// Check if the sample is inside. NOTE: for b>=0
|
||||
// the expression (UNSIGNED)a<(UNSIGNED)b is
|
||||
// equivalent to a>=0&&a<b.
|
||||
typedef int static_assert_size_matches[sizeof(ptrdiff_t)==sizeof(size_t)?1:-1];
|
||||
|
||||
if((size_t)x >= (size_t)w||(size_t)y >= (size_t)h) {
|
||||
switch(wrap_mode) {
|
||||
case 0: // Wrap
|
||||
if(!((w&(w-1))|(h&(h-1)))) {
|
||||
// Both w and h are powers of 2.
|
||||
x &= w-1;
|
||||
y &= h-1;
|
||||
} else {
|
||||
// For e.g. 1x1 images we might need to wrap several
|
||||
// times, hence 'while', instead of 'if'. Probably
|
||||
// still faster, than modulo.
|
||||
while(x < 0) x += w;
|
||||
while(y < 0) y += h;
|
||||
while(x >= w) x -= w;
|
||||
while(y >= h) y -= h;
|
||||
}
|
||||
break;
|
||||
case 1: // Clamp
|
||||
if(x < 0) x = 0;
|
||||
if(y < 0) y = 0;
|
||||
if(x >= w) x = w-1;
|
||||
if(y >= h) y = h-1;
|
||||
break;
|
||||
case 2: // Zero
|
||||
memset(output, 0, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy(output, pixels+s*y+4*x, 4);
|
||||
if((size_t)x >= (size_t)w||(size_t)y >= (size_t)h) {
|
||||
switch(wrap_mode) {
|
||||
case 0: // Wrap
|
||||
if(!((w&(w-1))|(h&(h-1)))) {
|
||||
// Both w and h are powers of 2.
|
||||
x &= w-1;
|
||||
y &= h-1;
|
||||
} else {
|
||||
// For e.g. 1x1 images we might need to wrap several
|
||||
// times, hence 'while', instead of 'if'. Probably
|
||||
// still faster, than modulo.
|
||||
while(x < 0) x += w;
|
||||
while(y < 0) y += h;
|
||||
while(x >= w) x -= w;
|
||||
while(y >= h) y -= h;
|
||||
}
|
||||
break;
|
||||
case 1: // Clamp
|
||||
if(x < 0) x = 0;
|
||||
if(y < 0) y = 0;
|
||||
if(x >= w) x = w-1;
|
||||
if(y >= h) y = h-1;
|
||||
break;
|
||||
case 2: // Zero
|
||||
memset(output, 0, 4);
|
||||
break;
|
||||
}
|
||||
}
|
||||
memcpy(output, pixels+s*y+4*x, 4);
|
||||
}
|
||||
|
||||
#define BLOCK 8
|
||||
|
||||
static void init_block(
|
||||
ptrdiff_t w, ptrdiff_t h,
|
||||
ptrdiff_t src_stride, const u8 *src_pixels,
|
||||
int wrap_mode, ptrdiff_t factor, float B, float C,
|
||||
ptrdiff_t x0, ptrdiff_t y0,
|
||||
float (*cx)[4], float (*cy)[4],
|
||||
ptrdiff_t *lx, ptrdiff_t *ly, ptrdiff_t *lx0, ptrdiff_t *ly0, ptrdiff_t *sx, ptrdiff_t *sy,
|
||||
u8 (*src)[(BLOCK+4)*4]) {
|
||||
// Precomputed coefficients for pixel weights
|
||||
// in the Mitchell-Netravali filter:
|
||||
// output = SUM(wij*pixel[i]*t^j)
|
||||
// where t is distance from pixel[1] to the
|
||||
// sampling position.
|
||||
float w00 = B/6.0f , w01 = -C-0.5f*B, w02 = 2.0f*C+0.5f*B , w03 = -C-B/6.0f ;
|
||||
float w10 = 1.0f-B/3.0f,/*w11 = 0.0f ,*/w12 = C+2.0f*B-3.0f , w13 = -C-1.5f*B+2.0f;
|
||||
float w20 = B/6.0f , w21 = C+0.5f*B, w22 = -2.0f*C-2.5f*B+3.0f, w23 = C+1.5f*B-2.0f;
|
||||
float /*w30 = 0.0f , w31 = 0.0f ,*/w32 = -C , w33 = C+B/6.0f ;
|
||||
// Express the sampling position as a rational
|
||||
// number num/den-1 (off by one, so that num is
|
||||
// always positive, since the C language does
|
||||
// not do Euclidean division). Sampling points
|
||||
// for both src and dst are assumed at pixel centers.
|
||||
ptrdiff_t den = 2*factor;
|
||||
float inv_den = 1.0f/(float)den;
|
||||
for(int dir = 0; dir < 2; ++dir) {
|
||||
ptrdiff_t num = (dir?2*y0+1+factor:2*x0+1+factor);
|
||||
ptrdiff_t *l = (dir?ly:lx), *l0 = (dir?ly0:lx0), *s = (dir?sy:sx);
|
||||
float (*c)[4] = (dir?cy:cx);
|
||||
(*l0) = num/den-2;
|
||||
num = num%den;
|
||||
for(ptrdiff_t i = 0, j = 0; i < BLOCK; ++i) {
|
||||
l[i] = j; // i-th dst pixel accesses src pixels (l0+l[i])..(l0+l[i]+3) in {x|y} direction.
|
||||
float t = (float)num*inv_den; // Fractional part of the sampling position.
|
||||
// Write out pixel weights.
|
||||
c[i][0] = ((w03*t+w02)*t +w01 )*t +w00 ;
|
||||
c[i][1] = ((w13*t+w12)*t/*+w11*/)*t +w10 ;
|
||||
c[i][2] = ((w23*t+w22)*t +w21 )*t +w20 ;
|
||||
c[i][3] = ((w33*t+w32)*t/*+w31*/)*t/*+w30*/;
|
||||
// Increment the sampling position.
|
||||
if((num += 2) >= den) {num -= den; j += 1;}
|
||||
}
|
||||
(*s) = l[BLOCK-1]+4; // Total sampled src pixels in {x|y} direction.
|
||||
}
|
||||
// Get a local copy of the source pixels.
|
||||
if((*lx0) >=0 && (*ly0) >= 0 && *lx0+(*sx) <= w && *ly0+(*sy) <= h) {
|
||||
for(ptrdiff_t iy = 0; iy < (*sy); ++iy)
|
||||
memcpy(src[iy], src_pixels+src_stride*((*ly0)+iy)+4*(*lx0), (size_t)(4*(*sx)));
|
||||
}
|
||||
else {
|
||||
for(ptrdiff_t iy = 0; iy < (*sy); ++iy) for(ptrdiff_t ix = 0; ix < (*sx); ++ix)
|
||||
load_sample(w, h, src_stride, src_pixels, wrap_mode, (*lx0)+ix, (*ly0)+iy, src[iy]+4*ix);
|
||||
}
|
||||
ptrdiff_t w, ptrdiff_t h,
|
||||
ptrdiff_t src_stride, const u8 *src_pixels,
|
||||
int wrap_mode, ptrdiff_t factor, float B, float C,
|
||||
ptrdiff_t x0, ptrdiff_t y0,
|
||||
float (*cx)[4], float (*cy)[4],
|
||||
ptrdiff_t *lx, ptrdiff_t *ly, ptrdiff_t *lx0, ptrdiff_t *ly0, ptrdiff_t *sx, ptrdiff_t *sy,
|
||||
u8 (*src)[(BLOCK+4)*4]) {
|
||||
// Precomputed coefficients for pixel weights
|
||||
// in the Mitchell-Netravali filter:
|
||||
// output = SUM(wij*pixel[i]*t^j)
|
||||
// where t is distance from pixel[1] to the
|
||||
// sampling position.
|
||||
float w00 = B/6.0f , w01 = -C-0.5f*B, w02 = 2.0f*C+0.5f*B , w03 = -C-B/6.0f ;
|
||||
float w10 = 1.0f-B/3.0f,/*w11 = 0.0f ,*/w12 = C+2.0f*B-3.0f , w13 = -C-1.5f*B+2.0f;
|
||||
float w20 = B/6.0f , w21 = C+0.5f*B, w22 = -2.0f*C-2.5f*B+3.0f, w23 = C+1.5f*B-2.0f;
|
||||
float /*w30 = 0.0f , w31 = 0.0f ,*/w32 = -C , w33 = C+B/6.0f ;
|
||||
// Express the sampling position as a rational
|
||||
// number num/den-1 (off by one, so that num is
|
||||
// always positive, since the C language does
|
||||
// not do Euclidean division). Sampling points
|
||||
// for both src and dst are assumed at pixel centers.
|
||||
ptrdiff_t den = 2*factor;
|
||||
float inv_den = 1.0f/(float)den;
|
||||
for(int dir = 0; dir < 2; ++dir) {
|
||||
ptrdiff_t num = (dir?2*y0+1+factor:2*x0+1+factor);
|
||||
ptrdiff_t *l = (dir?ly:lx), *l0 = (dir?ly0:lx0), *s = (dir?sy:sx);
|
||||
float (*c)[4] = (dir?cy:cx);
|
||||
(*l0) = num/den-2;
|
||||
num = num%den;
|
||||
for(ptrdiff_t i = 0, j = 0; i < BLOCK; ++i) {
|
||||
l[i] = j; // i-th dst pixel accesses src pixels (l0+l[i])..(l0+l[i]+3) in {x|y} direction.
|
||||
float t = (float)num*inv_den; // Fractional part of the sampling position.
|
||||
// Write out pixel weights.
|
||||
c[i][0] = ((w03*t+w02)*t +w01 )*t +w00 ;
|
||||
c[i][1] = ((w13*t+w12)*t/*+w11*/)*t +w10 ;
|
||||
c[i][2] = ((w23*t+w22)*t +w21 )*t +w20 ;
|
||||
c[i][3] = ((w33*t+w32)*t/*+w31*/)*t/*+w30*/;
|
||||
// Increment the sampling position.
|
||||
if((num += 2) >= den) {num -= den; j += 1;}
|
||||
}
|
||||
(*s) = l[BLOCK-1]+4; // Total sampled src pixels in {x|y} direction.
|
||||
}
|
||||
// Get a local copy of the source pixels.
|
||||
if((*lx0) >=0 && (*ly0) >= 0 && *lx0+(*sx) <= w && *ly0+(*sy) <= h) {
|
||||
for(ptrdiff_t iy = 0; iy < (*sy); ++iy)
|
||||
memcpy(src[iy], src_pixels+src_stride*((*ly0)+iy)+4*(*lx0), (size_t)(4*(*sx)));
|
||||
}
|
||||
else {
|
||||
for(ptrdiff_t iy = 0; iy < (*sy); ++iy) for(ptrdiff_t ix = 0; ix < (*sx); ++ix)
|
||||
load_sample(w, h, src_stride, src_pixels, wrap_mode, (*lx0)+ix, (*ly0)+iy, src[iy]+4*ix);
|
||||
}
|
||||
}
|
||||
|
||||
static void upscale_block_c(
|
||||
ptrdiff_t w, ptrdiff_t h,
|
||||
ptrdiff_t src_stride, const u8 *src_pixels,
|
||||
int wrap_mode, ptrdiff_t factor, float B, float C,
|
||||
ptrdiff_t x0, ptrdiff_t y0,
|
||||
u8 *dst_pixels) {
|
||||
float cx[BLOCK][4], cy[BLOCK][4];
|
||||
ptrdiff_t lx[BLOCK], ly[BLOCK], lx0, ly0, sx, sy;
|
||||
u8 src[BLOCK+4][(BLOCK+4)*4];
|
||||
float buf[2][BLOCK+4][BLOCK+4][4];
|
||||
init_block(
|
||||
w, h, src_stride, src_pixels, wrap_mode, factor, B, C, x0, y0,
|
||||
cx, cy, lx, ly, &lx0, &ly0, &sx, &sy, src);
|
||||
// Unpack source pixels.
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < sx; ++ix)
|
||||
for(ptrdiff_t k = 0; k < 4; ++k)
|
||||
buf[0][iy][ix][k] = (float)(int)src[iy][4*ix+k];
|
||||
// Horizontal pass.
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
#define S(i) (buf[0][iy][lx[ix]+i][k])
|
||||
float C0 = cx[ix][0], C1 = cx[ix][1], C2 = cx[ix][2], C3 = cx[ix][3];
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
for(ptrdiff_t k = 0; k < 4; ++k)
|
||||
buf[1][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3;
|
||||
#undef S
|
||||
}
|
||||
// Vertical pass.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy) {
|
||||
#define S(i) (buf[1][ly[iy]+i][ix][k])
|
||||
float C0 = cy[iy][0], C1 = cy[iy][1], C2 = cy[iy][2], C3 = cy[iy][3];
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix)
|
||||
for(ptrdiff_t k = 0; k < 4; ++k)
|
||||
buf[0][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3;
|
||||
#undef S
|
||||
}
|
||||
// Pack destination pixels.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
u8 pixel[4];
|
||||
for(ptrdiff_t k = 0; k < 4; ++k) {
|
||||
float C = buf[0][iy][ix][k];
|
||||
if(!(C>0.0f)) C = 0.0f;
|
||||
if(C>255.0f) C = 255.0f;
|
||||
pixel[k] = (u8)(int)(C+0.5f);
|
||||
}
|
||||
memcpy(dst_pixels+4*(BLOCK*iy+ix), pixel, 4);
|
||||
}
|
||||
ptrdiff_t w, ptrdiff_t h,
|
||||
ptrdiff_t src_stride, const u8 *src_pixels,
|
||||
int wrap_mode, ptrdiff_t factor, float B, float C,
|
||||
ptrdiff_t x0, ptrdiff_t y0,
|
||||
u8 *dst_pixels) {
|
||||
float cx[BLOCK][4], cy[BLOCK][4];
|
||||
ptrdiff_t lx[BLOCK], ly[BLOCK], lx0, ly0, sx, sy;
|
||||
u8 src[BLOCK+4][(BLOCK+4)*4];
|
||||
float buf[2][BLOCK+4][BLOCK+4][4];
|
||||
init_block(
|
||||
w, h, src_stride, src_pixels, wrap_mode, factor, B, C, x0, y0,
|
||||
cx, cy, lx, ly, &lx0, &ly0, &sx, &sy, src);
|
||||
// Unpack source pixels.
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < sx; ++ix)
|
||||
for(ptrdiff_t k = 0; k < 4; ++k)
|
||||
buf[0][iy][ix][k] = (float)(int)src[iy][4*ix+k];
|
||||
// Horizontal pass.
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
#define S(i) (buf[0][iy][lx[ix]+i][k])
|
||||
float C0 = cx[ix][0], C1 = cx[ix][1], C2 = cx[ix][2], C3 = cx[ix][3];
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
for(ptrdiff_t k = 0; k < 4; ++k)
|
||||
buf[1][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3;
|
||||
#undef S
|
||||
}
|
||||
// Vertical pass.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy) {
|
||||
#define S(i) (buf[1][ly[iy]+i][ix][k])
|
||||
float C0 = cy[iy][0], C1 = cy[iy][1], C2 = cy[iy][2], C3 = cy[iy][3];
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix)
|
||||
for(ptrdiff_t k = 0; k < 4; ++k)
|
||||
buf[0][iy][ix][k] = S(0)*C0+S(1)*C1+S(2)*C2+S(3)*C3;
|
||||
#undef S
|
||||
}
|
||||
// Pack destination pixels.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
u8 pixel[4];
|
||||
for(ptrdiff_t k = 0; k < 4; ++k) {
|
||||
float C = buf[0][iy][ix][k];
|
||||
if(!(C>0.0f)) C = 0.0f;
|
||||
if(C>255.0f) C = 255.0f;
|
||||
pixel[k] = (u8)(int)(C+0.5f);
|
||||
}
|
||||
memcpy(dst_pixels+4*(BLOCK*iy+ix), pixel, 4);
|
||||
}
|
||||
}
|
||||
|
||||
#if defined(_M_SSE)
|
||||
@@ -361,111 +361,111 @@ static void upscale_block_c(
|
||||
#endif
|
||||
|
||||
static void upscale_block_sse2(
|
||||
ptrdiff_t w, ptrdiff_t h,
|
||||
ptrdiff_t src_stride, const u8 *src_pixels,
|
||||
int wrap_mode, ptrdiff_t factor, float B, float C,
|
||||
ptrdiff_t x0, ptrdiff_t y0,
|
||||
u8 *dst_pixels) {
|
||||
float cx[BLOCK][4], cy[BLOCK][4];
|
||||
ptrdiff_t lx[BLOCK], ly[BLOCK], lx0, ly0, sx, sy;
|
||||
ALIGNED(16) u8 src[BLOCK+4][(BLOCK+4)*4];
|
||||
ALIGNED(16) float buf[2][BLOCK+4][BLOCK+4][4];
|
||||
init_block(
|
||||
w, h, src_stride, src_pixels, wrap_mode, factor, B, C, x0, y0,
|
||||
cx, cy, lx, ly, &lx0, &ly0, &sx, &sy, src);
|
||||
// Unpack source pixels.
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < sx; ++ix) {
|
||||
int pixel;
|
||||
memcpy(&pixel, src[iy]+4*ix, 4);
|
||||
__m128i C = _mm_cvtsi32_si128(pixel);
|
||||
C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0));
|
||||
C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0));
|
||||
_mm_storeu_ps(buf[0][iy][ix], _mm_cvtepi32_ps(C));
|
||||
}
|
||||
// Horizontal pass.
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
#define S(i) (buf[0][iy][lx[ix]+i])
|
||||
__m128 C0 = _mm_set1_ps(cx[ix][0]),
|
||||
C1 = _mm_set1_ps(cx[ix][1]),
|
||||
C2 = _mm_set1_ps(cx[ix][2]),
|
||||
C3 = _mm_set1_ps(cx[ix][3]);
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
_mm_storeu_ps(buf[1][iy][ix],
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2),
|
||||
_mm_mul_ps(_mm_loadu_ps(S(3)), C3)))));
|
||||
#undef S
|
||||
}
|
||||
// Vertical pass.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy) {
|
||||
#define S(i) (buf[1][ly[iy]+i][ix])
|
||||
__m128 C0 = _mm_set1_ps(cy[iy][0]),
|
||||
C1 = _mm_set1_ps(cy[iy][1]),
|
||||
C2 = _mm_set1_ps(cy[iy][2]),
|
||||
C3 = _mm_set1_ps(cy[iy][3]);
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix)
|
||||
_mm_storeu_ps(buf[0][iy][ix],
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2),
|
||||
_mm_mul_ps(_mm_loadu_ps(S(3)), C3)))));
|
||||
#undef S
|
||||
}
|
||||
// Pack destination pixels.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
__m128 C = _mm_loadu_ps(buf[0][iy][ix]);
|
||||
C = _mm_min_ps(_mm_max_ps(C, _mm_set1_ps(0.0f)), _mm_set1_ps(255.0f));
|
||||
C = _mm_add_ps(C, _mm_set1_ps(0.5f));
|
||||
__m128i R = _mm_cvttps_epi32(C);
|
||||
R = _mm_packus_epi16(R, R);
|
||||
R = _mm_packus_epi16(R, R);
|
||||
int pixel = _mm_cvtsi128_si32(R);
|
||||
memcpy(dst_pixels+4*(BLOCK*iy+ix), &pixel, 4);
|
||||
}
|
||||
ptrdiff_t w, ptrdiff_t h,
|
||||
ptrdiff_t src_stride, const u8 *src_pixels,
|
||||
int wrap_mode, ptrdiff_t factor, float B, float C,
|
||||
ptrdiff_t x0, ptrdiff_t y0,
|
||||
u8 *dst_pixels) {
|
||||
float cx[BLOCK][4], cy[BLOCK][4];
|
||||
ptrdiff_t lx[BLOCK], ly[BLOCK], lx0, ly0, sx, sy;
|
||||
ALIGNED(16) u8 src[BLOCK+4][(BLOCK+4)*4];
|
||||
ALIGNED(16) float buf[2][BLOCK+4][BLOCK+4][4];
|
||||
init_block(
|
||||
w, h, src_stride, src_pixels, wrap_mode, factor, B, C, x0, y0,
|
||||
cx, cy, lx, ly, &lx0, &ly0, &sx, &sy, src);
|
||||
// Unpack source pixels.
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < sx; ++ix) {
|
||||
int pixel;
|
||||
memcpy(&pixel, src[iy]+4*ix, 4);
|
||||
__m128i C = _mm_cvtsi32_si128(pixel);
|
||||
C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0));
|
||||
C = _mm_unpacklo_epi8(C, _mm_set1_epi32(0));
|
||||
_mm_storeu_ps(buf[0][iy][ix], _mm_cvtepi32_ps(C));
|
||||
}
|
||||
// Horizontal pass.
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
#define S(i) (buf[0][iy][lx[ix]+i])
|
||||
__m128 C0 = _mm_set1_ps(cx[ix][0]),
|
||||
C1 = _mm_set1_ps(cx[ix][1]),
|
||||
C2 = _mm_set1_ps(cx[ix][2]),
|
||||
C3 = _mm_set1_ps(cx[ix][3]);
|
||||
for(ptrdiff_t iy = 0; iy < sy; ++iy)
|
||||
_mm_storeu_ps(buf[1][iy][ix],
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2),
|
||||
_mm_mul_ps(_mm_loadu_ps(S(3)), C3)))));
|
||||
#undef S
|
||||
}
|
||||
// Vertical pass.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy) {
|
||||
#define S(i) (buf[1][ly[iy]+i][ix])
|
||||
__m128 C0 = _mm_set1_ps(cy[iy][0]),
|
||||
C1 = _mm_set1_ps(cy[iy][1]),
|
||||
C2 = _mm_set1_ps(cy[iy][2]),
|
||||
C3 = _mm_set1_ps(cy[iy][3]);
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix)
|
||||
_mm_storeu_ps(buf[0][iy][ix],
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(0)), C0),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(1)), C1),
|
||||
_mm_add_ps(_mm_mul_ps(_mm_loadu_ps(S(2)), C2),
|
||||
_mm_mul_ps(_mm_loadu_ps(S(3)), C3)))));
|
||||
#undef S
|
||||
}
|
||||
// Pack destination pixels.
|
||||
for(ptrdiff_t iy = 0; iy < BLOCK; ++iy)
|
||||
for(ptrdiff_t ix = 0; ix < BLOCK; ++ix) {
|
||||
__m128 C = _mm_loadu_ps(buf[0][iy][ix]);
|
||||
C = _mm_min_ps(_mm_max_ps(C, _mm_set1_ps(0.0f)), _mm_set1_ps(255.0f));
|
||||
C = _mm_add_ps(C, _mm_set1_ps(0.5f));
|
||||
__m128i R = _mm_cvttps_epi32(C);
|
||||
R = _mm_packus_epi16(R, R);
|
||||
R = _mm_packus_epi16(R, R);
|
||||
int pixel = _mm_cvtsi128_si32(R);
|
||||
memcpy(dst_pixels+4*(BLOCK*iy+ix), &pixel, 4);
|
||||
}
|
||||
}
|
||||
#endif // defined(_M_SSE)
|
||||
|
||||
static void upscale_cubic(
|
||||
ptrdiff_t width, ptrdiff_t height, ptrdiff_t src_stride_in_bytes, const void *src_pixels,
|
||||
ptrdiff_t dst_stride_in_bytes, void *dst_pixels,
|
||||
ptrdiff_t scale, float B, float C, int wrap_mode,
|
||||
ptrdiff_t x0, ptrdiff_t y0, ptrdiff_t x1, ptrdiff_t y1) {
|
||||
u8 pixels[BLOCK*BLOCK*4];
|
||||
for(ptrdiff_t y = y0; y < y1; y+= BLOCK)
|
||||
for(ptrdiff_t x = x0; x < x1; x+= BLOCK) {
|
||||
ptrdiff_t width, ptrdiff_t height, ptrdiff_t src_stride_in_bytes, const void *src_pixels,
|
||||
ptrdiff_t dst_stride_in_bytes, void *dst_pixels,
|
||||
ptrdiff_t scale, float B, float C, int wrap_mode,
|
||||
ptrdiff_t x0, ptrdiff_t y0, ptrdiff_t x1, ptrdiff_t y1) {
|
||||
u8 pixels[BLOCK*BLOCK*4];
|
||||
for(ptrdiff_t y = y0; y < y1; y+= BLOCK)
|
||||
for(ptrdiff_t x = x0; x < x1; x+= BLOCK) {
|
||||
#if defined(_M_SSE)
|
||||
upscale_block_sse2(width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels);
|
||||
upscale_block_sse2(width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels);
|
||||
#else
|
||||
upscale_block_c (width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels);
|
||||
upscale_block_c (width, height, src_stride_in_bytes, (const u8*)src_pixels, wrap_mode, scale, B, C, x, y, pixels);
|
||||
#endif
|
||||
for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK?y1-y:BLOCK), nx = (x1-x < BLOCK?x1-x:BLOCK); iy < ny; ++iy)
|
||||
memcpy((u8*)dst_pixels+dst_stride_in_bytes*(y+iy)+4*x, pixels+BLOCK*4*iy, (size_t)(4*nx));
|
||||
}
|
||||
for(ptrdiff_t iy = 0, ny = (y1-y < BLOCK?y1-y:BLOCK), nx = (x1-x < BLOCK?x1-x:BLOCK); iy < ny; ++iy)
|
||||
memcpy((u8*)dst_pixels+dst_stride_in_bytes*(y+iy)+4*x, pixels+BLOCK*4*iy, (size_t)(4*nx));
|
||||
}
|
||||
}
|
||||
|
||||
// End of pasted cubic upscaler.
|
||||
|
||||
void scaleBicubicBSpline(int factor, u32* data, u32* out, int w, int h, int l, int u) {
|
||||
const float B = 1.0f, C = 0.0f;
|
||||
const int wrap_mode = 0; // Clamp
|
||||
upscale_cubic(
|
||||
w, h, w*4, data,
|
||||
factor*w*4, out,
|
||||
factor, B, C, wrap_mode,
|
||||
0, factor*l, factor*w, factor*u);
|
||||
const float B = 1.0f, C = 0.0f;
|
||||
const int wrap_mode = 0; // Clamp
|
||||
upscale_cubic(
|
||||
w, h, w*4, data,
|
||||
factor*w*4, out,
|
||||
factor, B, C, wrap_mode,
|
||||
0, factor*l, factor*w, factor*u);
|
||||
}
|
||||
|
||||
void scaleBicubicMitchell(int factor, u32* data, u32* out, int w, int h, int l, int u) {
|
||||
const float B = 0.0f, C = 0.5f; // Actually, Catmull-Rom
|
||||
const int wrap_mode = 0; // Clamp
|
||||
upscale_cubic(
|
||||
w, h, w*4, data,
|
||||
factor*w*4, out,
|
||||
factor, B, C, wrap_mode,
|
||||
0, factor*l, factor*w, factor*u);
|
||||
const float B = 0.0f, C = 0.5f; // Actually, Catmull-Rom
|
||||
const int wrap_mode = 0; // Clamp
|
||||
upscale_cubic(
|
||||
w, h, w*4, data,
|
||||
factor*w*4, out,
|
||||
factor, B, C, wrap_mode,
|
||||
0, factor*l, factor*w, factor*u);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////// Bilinear scaling
|
||||
|
||||
Reference in new issue
Block a user