summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohann <johann.koenig@duck.com>2018-11-13 13:39:43 -0800
committerJohann <johann.koenig@duck.com>2018-11-14 11:46:58 -0800
commit9f4d4a3f4924401153ddf7545be185a0edb8e829 (patch)
tree1bb15f6491b87cc509057076aeb6e0b0d048ded6
parent0fd7514b552e8ff04e257cb43c975f71847b3d81 (diff)
downloadlibwebp-9f4d4a3f4924401153ddf7545be185a0edb8e829.tar.gz
neon: GetResidualCost
Direct copy of sse2. Slight improvement because neon has abs(). flower.ppm had minimal improvement. Somewhat expected because GetResidualCost_C is only ~3.6% mug.ppm had a better improvement because GetResidualCost_C is almost 9%. C 2.150 NEON 2.130 BUG=b/118740850 Change-Id: Ibc0dd97a81596635f5599cf568205974b4fd2597
-rw-r--r--src/dsp/cost_neon.c58
1 files changed, 58 insertions, 0 deletions
diff --git a/src/dsp/cost_neon.c b/src/dsp/cost_neon.c
index faa6e196..8cc8ce58 100644
--- a/src/dsp/cost_neon.c
+++ b/src/dsp/cost_neon.c
@@ -48,6 +48,63 @@ static void SetResidualCoeffs_NEON(const int16_t* const coeffs,
res->coeffs = coeffs;
}
+static int GetResidualCost_NEON(int ctx0, const VP8Residual* const res) {
+ uint8_t levels[16], ctxs[16];
+ uint16_t abs_levels[16];
+ int n = res->first;
+ // should be prob[VP8EncBands[n]], but it's equivalent for n=0 or 1
+ const int p0 = res->prob[n][ctx0][0];
+ CostArrayPtr const costs = res->costs;
+ const uint16_t* t = costs[n][ctx0];
+ // bit_cost(1, p0) is already incorporated in t[] tables, but only if ctx != 0
+ // (as required by the syntax). For ctx0 == 0, we need to add it here or it'll
+ // be missing during the loop.
+ int cost = (ctx0 == 0) ? VP8BitCost(1, p0) : 0;
+
+ if (res->last < 0) {
+ return VP8BitCost(0, p0);
+ }
+
+ { // precompute clamped levels and contexts, packed to 8b.
+ const uint8x16_t kCst2 = vdupq_n_u8(2);
+ const uint8x16_t kCst67 = vdupq_n_u8(MAX_VARIABLE_LEVEL);
+ const int16x8_t c0 = vld1q_s16(res->coeffs);
+ const int16x8_t c1 = vld1q_s16(res->coeffs + 8);
+ const uint16x8_t E0 = vreinterpretq_u16_s16(vabsq_s16(c0));
+ const uint16x8_t E1 = vreinterpretq_u16_s16(vabsq_s16(c1));
+ const uint8x16_t F = vcombine_u8(vqmovn_u16(E0), vqmovn_u16(E1));
+ const uint8x16_t G = vminq_u8(F, kCst2); // context = 0,1,2
+ const uint8x16_t H = vminq_u8(F, kCst67); // clamp_level in [0..67]
+
+ vst1q_u8(ctxs, G);
+ vst1q_u8(levels, H);
+
+ vst1q_u16(abs_levels, E0);
+ vst1q_u16(abs_levels + 8, E1);
+ }
+ for (; n < res->last; ++n) {
+ const int ctx = ctxs[n];
+ const int level = levels[n];
+ const int flevel = abs_levels[n]; // full level
+ cost += VP8LevelFixedCosts[flevel] + t[level]; // simplified VP8LevelCost()
+ t = costs[n + 1][ctx];
+ }
+ // Last coefficient is always non-zero
+ {
+ const int level = levels[n];
+ const int flevel = abs_levels[n];
+ assert(flevel != 0);
+ cost += VP8LevelFixedCosts[flevel] + t[level];
+ if (n < 15) {
+ const int b = VP8EncBands[n + 1];
+ const int ctx = ctxs[n];
+ const int last_p0 = res->prob[b][ctx][0];
+ cost += VP8BitCost(0, last_p0);
+ }
+ }
+ return cost;
+}
+
//------------------------------------------------------------------------------
// Entry point
@@ -55,6 +112,7 @@ extern void VP8EncDspCostInitNEON(void);
WEBP_TSAN_IGNORE_FUNCTION void VP8EncDspCostInitNEON(void) {
VP8SetResidualCoeffs = SetResidualCoeffs_NEON;
+ VP8GetResidualCost = GetResidualCost_NEON;
}
#else // !WEBP_USE_NEON