Make the lossless predictors work on a batch of pixels.

Change-Id: Ieaee34f1f97c375b9e97ef7e9df60aed353dffa1
This commit is contained in:
Vincent Rabaud
2016-11-28 17:12:05 +01:00
parent bc18ebad2e
commit 4239a1489c
8 changed files with 236 additions and 105 deletions

View File

@ -27,11 +27,6 @@
//------------------------------------------------------------------------------
// Image transforms.
// In-place sum of each component with mod 256.
static WEBP_INLINE void AddPixelsEq(uint32_t* a, uint32_t b) {
*a = VP8LAddPixels(*a, b);
}
static WEBP_INLINE uint32_t Average2(uint32_t a0, uint32_t a1) {
return (((a0 ^ a1) & 0xfefefefeu) >> 1) + (a0 & a1);
}
@ -172,21 +167,33 @@ static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
return pred;
}
GENERATE_PREDICTOR_ADD(0)
GENERATE_PREDICTOR_ADD(1)
GENERATE_PREDICTOR_ADD(2)
GENERATE_PREDICTOR_ADD(3)
GENERATE_PREDICTOR_ADD(4)
GENERATE_PREDICTOR_ADD(5)
GENERATE_PREDICTOR_ADD(6)
GENERATE_PREDICTOR_ADD(7)
GENERATE_PREDICTOR_ADD(8)
GENERATE_PREDICTOR_ADD(9)
GENERATE_PREDICTOR_ADD(10)
GENERATE_PREDICTOR_ADD(11)
GENERATE_PREDICTOR_ADD(12)
GENERATE_PREDICTOR_ADD(13)
//------------------------------------------------------------------------------
// Inverse prediction.
static void PredictorInverseTransform(const VP8LTransform* const transform,
int y_start, int y_end, uint32_t* data) {
int y_start, int y_end,
const uint32_t* in, uint32_t* out) {
const int width = transform->xsize_;
if (y_start == 0) { // First Row follows the L (mode=1) mode.
int x;
const uint32_t pred0 = Predictor0(data[-1], NULL);
AddPixelsEq(data, pred0);
for (x = 1; x < width; ++x) {
const uint32_t pred1 = Predictor1(data[x - 1], NULL);
AddPixelsEq(data + x, pred1);
}
data += width;
PredictorAdd0(in, NULL, 1, out);
PredictorAdd1(in + 1, NULL, width - 1, out + 1);
in += width;
out += width;
++y_start;
}
@ -194,36 +201,26 @@ static void PredictorInverseTransform(const VP8LTransform* const transform,
int y = y_start;
const int tile_width = 1 << transform->bits_;
const int mask = tile_width - 1;
const int safe_width = width & ~mask;
const int tiles_per_row = VP8LSubSampleSize(width, transform->bits_);
const uint32_t* pred_mode_base =
transform->data_ + (y >> transform->bits_) * tiles_per_row;
while (y < y_end) {
const uint32_t pred2 = Predictor2(data[-1], data - width);
const uint32_t* pred_mode_src = pred_mode_base;
VP8LPredictorFunc pred_func;
int x = 1;
int t = 1;
// First pixel follows the T (mode=2) mode.
AddPixelsEq(data, pred2);
PredictorAdd2(in, out - width, 1, out);
// .. the rest:
while (x < safe_width) {
pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf];
for (; t < tile_width; ++t, ++x) {
const uint32_t pred = pred_func(data[x - 1], data + x - width);
AddPixelsEq(data + x, pred);
}
t = 0;
while (x < width) {
const VP8LPredictorAddSubFunc pred_func =
VP8LPredictorsAdd[((*pred_mode_src++) >> 8) & 0xf];
int x_end = (x & ~mask) + tile_width;
if (x_end > width) x_end = width;
pred_func(in + x, out + x - width, x_end - x, out + x);
x = x_end;
}
if (x < width) {
pred_func = VP8LPredictors[((*pred_mode_src++) >> 8) & 0xf];
for (; x < width; ++x) {
const uint32_t pred = pred_func(data[x - 1], data + x - width);
AddPixelsEq(data + x, pred);
}
}
data += width;
in += width;
out += width;
++y;
if ((y & mask) == 0) { // Use the same mask, since tiles are squares.
pred_mode_base += tiles_per_row;
@ -375,11 +372,7 @@ void VP8LInverseTransform(const VP8LTransform* const transform,
VP8LAddGreenToBlueAndRed(in, (row_end - row_start) * width, out);
break;
case PREDICTOR_TRANSFORM:
// TODO(vrabaud): parallelize transform predictors.
if (in != out) {
memcpy(out, in, (row_end - row_start) * width * sizeof(*out));
}
PredictorInverseTransform(transform, row_start, row_end, out);
PredictorInverseTransform(transform, row_start, row_end, in, out);
if (row_end != transform->ysize_) {
// The last predicted row in this iteration will be the top-pred row
// for the first row in next iteration.
@ -566,6 +559,7 @@ void VP8LConvertFromBGRA(const uint32_t* const in_data, int num_pixels,
//------------------------------------------------------------------------------
VP8LProcessDecBlueAndRedFunc VP8LAddGreenToBlueAndRed;
VP8LPredictorAddSubFunc VP8LPredictorsAdd[16];
VP8LPredictorFunc VP8LPredictors[16];
VP8LTransformColorInverseFunc VP8LTransformColorInverse;
@ -607,6 +601,23 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInit(void) {
VP8LPredictors[14] = Predictor0; // <- padding security sentinels
VP8LPredictors[15] = Predictor0;
VP8LPredictorsAdd[0] = PredictorAdd0;
VP8LPredictorsAdd[1] = PredictorAdd1;
VP8LPredictorsAdd[2] = PredictorAdd2;
VP8LPredictorsAdd[3] = PredictorAdd3;
VP8LPredictorsAdd[4] = PredictorAdd4;
VP8LPredictorsAdd[5] = PredictorAdd5;
VP8LPredictorsAdd[6] = PredictorAdd6;
VP8LPredictorsAdd[7] = PredictorAdd7;
VP8LPredictorsAdd[8] = PredictorAdd8;
VP8LPredictorsAdd[9] = PredictorAdd9;
VP8LPredictorsAdd[10] = PredictorAdd10;
VP8LPredictorsAdd[11] = PredictorAdd11;
VP8LPredictorsAdd[12] = PredictorAdd12;
VP8LPredictorsAdd[13] = PredictorAdd13;
VP8LPredictorsAdd[14] = PredictorAdd0; // <- padding security sentinels
VP8LPredictorsAdd[15] = PredictorAdd0;
VP8LAddGreenToBlueAndRed = VP8LAddGreenToBlueAndRed_C;
VP8LTransformColorInverse = VP8LTransformColorInverse_C;

View File

@ -34,6 +34,10 @@ extern "C" {
typedef uint32_t (*VP8LPredictorFunc)(uint32_t left, const uint32_t* const top);
extern VP8LPredictorFunc VP8LPredictors[16];
typedef void (*VP8LPredictorAddSubFunc)(const uint32_t* in,
const uint32_t* upper, int num_pixels,
uint32_t* out);
extern VP8LPredictorAddSubFunc VP8LPredictorsAdd[16];
typedef void (*VP8LProcessDecBlueAndRedFunc)(const uint32_t* src,
int num_pixels, uint32_t* dst);
@ -143,6 +147,8 @@ void VP8LCollectColorBlueTransforms_C(const uint32_t* argb, int stride,
int green_to_blue, int red_to_blue,
int histo[]);
extern VP8LPredictorAddSubFunc VP8LPredictorsSub[16];
// -----------------------------------------------------------------------------
// Huffman-cost related functions.

View File

@ -174,6 +174,34 @@ uint32_t VP8LSubPixels(uint32_t a, uint32_t b) {
}
//------------------------------------------------------------------------------
// Transform-related functions use din both encoding and decoding.
// Macros used to create a batch predictor that iteratively uses a
// one-pixel predictor.
// The predictor is added to the output pixel (which
// is therefore considered as a residual) to get the final prediction.
#define GENERATE_PREDICTOR_ADD(X) \
static void PredictorAdd##X(const uint32_t* in, const uint32_t* upper, \
int num_pixels, uint32_t* out) { \
int x; \
for (x = 0; x < num_pixels; ++x) { \
const uint32_t pred = VP8LPredictors[(X)](out[x - 1], upper + x); \
out[x] = VP8LAddPixels(in[x], pred); \
} \
}
// It subtracts the prediction from the input pixel and stores the residual
// in the output pixel.
#define GENERATE_PREDICTOR_SUB(X) \
static void PredictorSub##X(const uint32_t* in, const uint32_t* upper, \
int num_pixels, uint32_t* out) { \
int x; \
for (x = 0; x < num_pixels; ++x) { \
const uint32_t pred = VP8LPredictors[(X)](in[x - 1], upper + x); \
out[x] = VP8LSubPixels(in[x], pred); \
} \
}
#ifdef __cplusplus
} // extern "C"

View File

@ -665,6 +665,21 @@ static void HistogramAdd(const VP8LHistogram* const a,
//------------------------------------------------------------------------------
GENERATE_PREDICTOR_SUB(0)
GENERATE_PREDICTOR_SUB(1)
GENERATE_PREDICTOR_SUB(2)
GENERATE_PREDICTOR_SUB(3)
GENERATE_PREDICTOR_SUB(4)
GENERATE_PREDICTOR_SUB(5)
GENERATE_PREDICTOR_SUB(6)
GENERATE_PREDICTOR_SUB(7)
GENERATE_PREDICTOR_SUB(8)
GENERATE_PREDICTOR_SUB(9)
GENERATE_PREDICTOR_SUB(10)
GENERATE_PREDICTOR_SUB(11)
GENERATE_PREDICTOR_SUB(12)
GENERATE_PREDICTOR_SUB(13)
VP8LProcessEncBlueAndRedFunc VP8LSubtractGreenFromBlueAndRed;
VP8LTransformColorFunc VP8LTransformColor;
@ -686,6 +701,8 @@ VP8LHistogramAddFunc VP8LHistogramAdd;
VP8LVectorMismatchFunc VP8LVectorMismatch;
VP8LPredictorAddSubFunc VP8LPredictorsSub[16];
extern void VP8LEncDspInitSSE2(void);
extern void VP8LEncDspInitSSE41(void);
extern void VP8LEncDspInitNEON(void);
@ -722,6 +739,23 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LEncDspInit(void) {
VP8LVectorMismatch = VectorMismatch;
VP8LPredictorsSub[0] = PredictorSub0;
VP8LPredictorsSub[1] = PredictorSub1;
VP8LPredictorsSub[2] = PredictorSub2;
VP8LPredictorsSub[3] = PredictorSub3;
VP8LPredictorsSub[4] = PredictorSub4;
VP8LPredictorsSub[5] = PredictorSub5;
VP8LPredictorsSub[6] = PredictorSub6;
VP8LPredictorsSub[7] = PredictorSub7;
VP8LPredictorsSub[8] = PredictorSub8;
VP8LPredictorsSub[9] = PredictorSub9;
VP8LPredictorsSub[10] = PredictorSub10;
VP8LPredictorsSub[11] = PredictorSub11;
VP8LPredictorsSub[12] = PredictorSub12;
VP8LPredictorsSub[13] = PredictorSub13;
VP8LPredictorsSub[14] = PredictorSub0; // <- padding security sentinels
VP8LPredictorsSub[15] = PredictorSub0;
// If defined, use CPUInfo() to overwrite some pointers with faster versions.
if (VP8GetCPUInfo != NULL) {
#if defined(WEBP_USE_SSE2)

View File

@ -17,6 +17,7 @@
#include "./common_sse2.h"
#include "./lossless.h"
#include "./lossless_common.h"
#include <assert.h>
#include <emmintrin.h>
@ -154,6 +155,17 @@ static uint32_t Predictor13(uint32_t left, const uint32_t* const top) {
return pred;
}
// TODO(vrabaud): implement those functions in SSE.
GENERATE_PREDICTOR_ADD(5)
GENERATE_PREDICTOR_ADD(6)
GENERATE_PREDICTOR_ADD(7)
GENERATE_PREDICTOR_ADD(8)
GENERATE_PREDICTOR_ADD(9)
GENERATE_PREDICTOR_ADD(10)
GENERATE_PREDICTOR_ADD(11)
GENERATE_PREDICTOR_ADD(12)
GENERATE_PREDICTOR_ADD(13)
//------------------------------------------------------------------------------
// Subtract-Green Transform
@ -394,6 +406,16 @@ WEBP_TSAN_IGNORE_FUNCTION void VP8LDspInitSSE2(void) {
VP8LPredictors[12] = Predictor12;
VP8LPredictors[13] = Predictor13;
VP8LPredictorsAdd[5] = PredictorAdd5;
VP8LPredictorsAdd[6] = PredictorAdd6;
VP8LPredictorsAdd[7] = PredictorAdd7;
VP8LPredictorsAdd[8] = PredictorAdd8;
VP8LPredictorsAdd[9] = PredictorAdd9;
VP8LPredictorsAdd[10] = PredictorAdd10;
VP8LPredictorsAdd[11] = PredictorAdd11;
VP8LPredictorsAdd[12] = PredictorAdd12;
VP8LPredictorsAdd[13] = PredictorAdd13;
VP8LAddGreenToBlueAndRed = AddGreenToBlueAndRed;
VP8LTransformColorInverse = TransformColorInverse;