#include "src/dsp/dsp.h"
#if defined(WEBP_USE_MSA) && !defined(WEBP_REDUCE_SIZE)
#include <assert.h>
#include "src/utils/rescaler_utils.h"
#include "src/dsp/msa_macro.h"
#define ROUNDER …
#define MULT_FIX …
#define MULT_FIX_FLOOR …
#define CALC_MULT_FIX_16 …
#define CALC_MULT_FIX_4 …
#define CALC_MULT_FIX1_16 …
#define CALC_MULT_FIX1_4 …
#define CALC_MULT_FIX2_16 …
#define CALC_MULT_FIX2_4 …
static WEBP_INLINE void ExportRowExpand_0(const uint32_t* frow, uint8_t* dst,
int length,
WebPRescaler* const wrk) {
const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale);
const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX);
const v4i32 zero = { 0 };
while (length >= 16) {
v4u32 src0, src1, src2, src3;
v16u8 out;
LD_UW4(frow, 4, src0, src1, src2, src3);
CALC_MULT_FIX_16(src0, src1, src2, src3, scale, shift, out);
ST_UB(out, dst);
length -= 16;
frow += 16;
dst += 16;
}
if (length > 0) {
int x_out;
if (length >= 12) {
uint32_t val0_m, val1_m, val2_m;
v4u32 src0, src1, src2;
LD_UW3(frow, 4, src0, src1, src2);
CALC_MULT_FIX_4(src0, scale, shift, val0_m);
CALC_MULT_FIX_4(src1, scale, shift, val1_m);
CALC_MULT_FIX_4(src2, scale, shift, val2_m);
SW3(val0_m, val1_m, val2_m, dst, 4);
length -= 12;
frow += 12;
dst += 12;
} else if (length >= 8) {
uint32_t val0_m, val1_m;
v4u32 src0, src1;
LD_UW2(frow, 4, src0, src1);
CALC_MULT_FIX_4(src0, scale, shift, val0_m);
CALC_MULT_FIX_4(src1, scale, shift, val1_m);
SW2(val0_m, val1_m, dst, 4);
length -= 8;
frow += 8;
dst += 8;
} else if (length >= 4) {
uint32_t val0_m;
const v4u32 src0 = LD_UW(frow);
CALC_MULT_FIX_4(src0, scale, shift, val0_m);
SW(val0_m, dst);
length -= 4;
frow += 4;
dst += 4;
}
for (x_out = 0; x_out < length; ++x_out) {
const uint32_t J = frow[x_out];
const int v = (int)MULT_FIX(J, wrk->fy_scale);
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
}
}
}
static WEBP_INLINE void ExportRowExpand_1(const uint32_t* frow, uint32_t* irow,
uint8_t* dst, int length,
WebPRescaler* const wrk) {
const uint32_t B = WEBP_RESCALER_FRAC(-wrk->y_accum, wrk->y_sub);
const uint32_t A = (uint32_t)(WEBP_RESCALER_ONE - B);
const v4i32 B1 = __msa_fill_w(B);
const v4i32 A1 = __msa_fill_w(A);
const v4i32 AB = __msa_ilvr_w(A1, B1);
const v4u32 scale = (v4u32)__msa_fill_w(wrk->fy_scale);
const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX);
while (length >= 16) {
v4u32 frow0, frow1, frow2, frow3, irow0, irow1, irow2, irow3;
v16u8 t0, t1, t2, t3, t4, t5;
LD_UW4(frow, 4, frow0, frow1, frow2, frow3);
LD_UW4(irow, 4, irow0, irow1, irow2, irow3);
CALC_MULT_FIX2_16(frow0, frow1, irow0, irow1, AB, scale, shift, t0, t1);
CALC_MULT_FIX2_16(frow2, frow3, irow2, irow3, AB, scale, shift, t2, t3);
PCKEV_B2_UB(t1, t0, t3, t2, t4, t5);
t0 = (v16u8)__msa_pckev_b((v16i8)t5, (v16i8)t4);
ST_UB(t0, dst);
frow += 16;
irow += 16;
dst += 16;
length -= 16;
}
if (length > 0) {
int x_out;
if (length >= 12) {
uint32_t val0_m, val1_m, val2_m;
v4u32 frow0, frow1, frow2, irow0, irow1, irow2;
LD_UW3(frow, 4, frow0, frow1, frow2);
LD_UW3(irow, 4, irow0, irow1, irow2);
CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m);
CALC_MULT_FIX2_4(frow1, irow1, AB, scale, shift, val1_m);
CALC_MULT_FIX2_4(frow2, irow2, AB, scale, shift, val2_m);
SW3(val0_m, val1_m, val2_m, dst, 4);
frow += 12;
irow += 12;
dst += 12;
length -= 12;
} else if (length >= 8) {
uint32_t val0_m, val1_m;
v4u32 frow0, frow1, irow0, irow1;
LD_UW2(frow, 4, frow0, frow1);
LD_UW2(irow, 4, irow0, irow1);
CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m);
CALC_MULT_FIX2_4(frow1, irow1, AB, scale, shift, val1_m);
SW2(val0_m, val1_m, dst, 4);
frow += 4;
irow += 4;
dst += 4;
length -= 4;
} else if (length >= 4) {
uint32_t val0_m;
const v4u32 frow0 = LD_UW(frow + 0);
const v4u32 irow0 = LD_UW(irow + 0);
CALC_MULT_FIX2_4(frow0, irow0, AB, scale, shift, val0_m);
SW(val0_m, dst);
frow += 4;
irow += 4;
dst += 4;
length -= 4;
}
for (x_out = 0; x_out < length; ++x_out) {
const uint64_t I = (uint64_t)A * frow[x_out]
+ (uint64_t)B * irow[x_out];
const uint32_t J = (uint32_t)((I + ROUNDER) >> WEBP_RESCALER_RFIX);
const int v = (int)MULT_FIX(J, wrk->fy_scale);
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
}
}
}
static void RescalerExportRowExpand_MIPSdspR2(WebPRescaler* const wrk) {
uint8_t* dst = wrk->dst;
rescaler_t* irow = wrk->irow;
const int x_out_max = wrk->dst_width * wrk->num_channels;
const rescaler_t* frow = wrk->frow;
assert(!WebPRescalerOutputDone(wrk));
assert(wrk->y_accum <= 0);
assert(wrk->y_expand);
assert(wrk->y_sub != 0);
if (wrk->y_accum == 0) {
ExportRowExpand_0(frow, dst, x_out_max, wrk);
} else {
ExportRowExpand_1(frow, irow, dst, x_out_max, wrk);
}
}
#if 0
static WEBP_INLINE void ExportRowShrink_0(const uint32_t* frow, uint32_t* irow,
uint8_t* dst, int length,
const uint32_t yscale,
WebPRescaler* const wrk) {
const v4u32 y_scale = (v4u32)__msa_fill_w(yscale);
const v4u32 fxyscale = (v4u32)__msa_fill_w(wrk->fxy_scale);
const v4u32 shiftval = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX);
const v4i32 zero = { 0 };
while (length >= 16) {
v4u32 src0, src1, src2, src3, frac0, frac1, frac2, frac3;
v16u8 out;
LD_UW4(frow, 4, src0, src1, src2, src3);
CALC_MULT_FIX1_16(src0, src1, src2, src3, y_scale, shiftval,
frac0, frac1, frac2, frac3);
LD_UW4(irow, 4, src0, src1, src2, src3);
SUB4(src0, frac0, src1, frac1, src2, frac2, src3, frac3,
src0, src1, src2, src3);
CALC_MULT_FIX_16(src0, src1, src2, src3, fxyscale, shiftval, out);
ST_UB(out, dst);
ST_UW4(frac0, frac1, frac2, frac3, irow, 4);
frow += 16;
irow += 16;
dst += 16;
length -= 16;
}
if (length > 0) {
int x_out;
if (length >= 12) {
uint32_t val0_m, val1_m, val2_m;
v4u32 src0, src1, src2, frac0, frac1, frac2;
LD_UW3(frow, 4, src0, src1, src2);
CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0);
CALC_MULT_FIX1_4(src1, y_scale, shiftval, frac1);
CALC_MULT_FIX1_4(src2, y_scale, shiftval, frac2);
LD_UW3(irow, 4, src0, src1, src2);
SUB3(src0, frac0, src1, frac1, src2, frac2, src0, src1, src2);
CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m);
CALC_MULT_FIX_4(src1, fxyscale, shiftval, val1_m);
CALC_MULT_FIX_4(src2, fxyscale, shiftval, val2_m);
SW3(val0_m, val1_m, val2_m, dst, 4);
ST_UW3(frac0, frac1, frac2, irow, 4);
frow += 12;
irow += 12;
dst += 12;
length -= 12;
} else if (length >= 8) {
uint32_t val0_m, val1_m;
v4u32 src0, src1, frac0, frac1;
LD_UW2(frow, 4, src0, src1);
CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0);
CALC_MULT_FIX1_4(src1, y_scale, shiftval, frac1);
LD_UW2(irow, 4, src0, src1);
SUB2(src0, frac0, src1, frac1, src0, src1);
CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m);
CALC_MULT_FIX_4(src1, fxyscale, shiftval, val1_m);
SW2(val0_m, val1_m, dst, 4);
ST_UW2(frac0, frac1, irow, 4);
frow += 8;
irow += 8;
dst += 8;
length -= 8;
} else if (length >= 4) {
uint32_t val0_m;
v4u32 frac0;
v4u32 src0 = LD_UW(frow);
CALC_MULT_FIX1_4(src0, y_scale, shiftval, frac0);
src0 = LD_UW(irow);
src0 = src0 - frac0;
CALC_MULT_FIX_4(src0, fxyscale, shiftval, val0_m);
SW(val0_m, dst);
ST_UW(frac0, irow);
frow += 4;
irow += 4;
dst += 4;
length -= 4;
}
for (x_out = 0; x_out < length; ++x_out) {
const uint32_t frac = (uint32_t)MULT_FIX_FLOOR(frow[x_out], yscale);
const int v = (int)MULT_FIX(irow[x_out] - frac, wrk->fxy_scale);
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
irow[x_out] = frac;
}
}
}
static WEBP_INLINE void ExportRowShrink_1(uint32_t* irow, uint8_t* dst,
int length,
WebPRescaler* const wrk) {
const v4u32 scale = (v4u32)__msa_fill_w(wrk->fxy_scale);
const v4u32 shift = (v4u32)__msa_fill_w(WEBP_RESCALER_RFIX);
const v4i32 zero = { 0 };
while (length >= 16) {
v4u32 src0, src1, src2, src3;
v16u8 dst0;
LD_UW4(irow, 4, src0, src1, src2, src3);
CALC_MULT_FIX_16(src0, src1, src2, src3, scale, shift, dst0);
ST_UB(dst0, dst);
ST_SW4(zero, zero, zero, zero, irow, 4);
length -= 16;
irow += 16;
dst += 16;
}
if (length > 0) {
int x_out;
if (length >= 12) {
uint32_t val0_m, val1_m, val2_m;
v4u32 src0, src1, src2;
LD_UW3(irow, 4, src0, src1, src2);
CALC_MULT_FIX_4(src0, scale, shift, val0_m);
CALC_MULT_FIX_4(src1, scale, shift, val1_m);
CALC_MULT_FIX_4(src2, scale, shift, val2_m);
SW3(val0_m, val1_m, val2_m, dst, 4);
ST_SW3(zero, zero, zero, irow, 4);
length -= 12;
irow += 12;
dst += 12;
} else if (length >= 8) {
uint32_t val0_m, val1_m;
v4u32 src0, src1;
LD_UW2(irow, 4, src0, src1);
CALC_MULT_FIX_4(src0, scale, shift, val0_m);
CALC_MULT_FIX_4(src1, scale, shift, val1_m);
SW2(val0_m, val1_m, dst, 4);
ST_SW2(zero, zero, irow, 4);
length -= 8;
irow += 8;
dst += 8;
} else if (length >= 4) {
uint32_t val0_m;
const v4u32 src0 = LD_UW(irow + 0);
CALC_MULT_FIX_4(src0, scale, shift, val0_m);
SW(val0_m, dst);
ST_SW(zero, irow);
length -= 4;
irow += 4;
dst += 4;
}
for (x_out = 0; x_out < length; ++x_out) {
const int v = (int)MULT_FIX(irow[x_out], wrk->fxy_scale);
dst[x_out] = (v > 255) ? 255u : (uint8_t)v;
irow[x_out] = 0;
}
}
}
static void RescalerExportRowShrink_MIPSdspR2(WebPRescaler* const wrk) {
uint8_t* dst = wrk->dst;
rescaler_t* irow = wrk->irow;
const int x_out_max = wrk->dst_width * wrk->num_channels;
const rescaler_t* frow = wrk->frow;
const uint32_t yscale = wrk->fy_scale * (-wrk->y_accum);
assert(!WebPRescalerOutputDone(wrk));
assert(wrk->y_accum <= 0);
assert(!wrk->y_expand);
if (yscale) {
ExportRowShrink_0(frow, irow, dst, x_out_max, yscale, wrk);
} else {
ExportRowShrink_1(irow, dst, x_out_max, wrk);
}
}
#endif
extern void WebPRescalerDspInitMSA(void);
WEBP_TSAN_IGNORE_FUNCTION void WebPRescalerDspInitMSA(void) {
WebPRescalerExportRowExpand = RescalerExportRowExpand_MIPSdspR2;
}
#else
WEBP_DSP_INIT_STUB(WebPRescalerDspInitMSA)
#endif