Speed-up: Make sure we only initialize histograms when needed.

Also, histograms in a HistogramSet can be initialized all
at once.

Change-Id: Ibbfa6034dce58dca8bb9113487e2ae507222ce7d
This commit is contained in:
Vincent Rabaud 2018-10-30 20:33:20 +01:00
parent b6284d8247
commit 6752904b2f
5 changed files with 67 additions and 16 deletions

View File

@ -67,7 +67,7 @@ static int CostModelBuild(CostModel* const m, int xsize, int cache_bits,
// The following code is similar to VP8LHistogramCreate but converts the // The following code is similar to VP8LHistogramCreate but converts the
// distance to plane code. // distance to plane code.
VP8LHistogramInit(histo, cache_bits); VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1);
while (VP8LRefsCursorOk(&c)) { while (VP8LRefsCursorOk(&c)) {
VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode, VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode,
xsize); xsize);

View File

@ -715,6 +715,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality,
for (i = 0; i <= cache_bits_max; ++i) { for (i = 0; i <= cache_bits_max; ++i) {
histos[i] = VP8LAllocateHistogram(i); histos[i] = VP8LAllocateHistogram(i);
if (histos[i] == NULL) goto Error; if (histos[i] == NULL) goto Error;
VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1);
if (i == 0) continue; if (i == 0) continue;
cc_init[i] = VP8LColorCacheInit(&hashers[i], i); cc_init[i] = VP8LColorCacheInit(&hashers[i], i);
if (!cc_init[i]) goto Error; if (!cc_init[i]) goto Error;

View File

@ -93,9 +93,19 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
VP8LHistogramStoreRefs(refs, p); VP8LHistogramStoreRefs(refs, p);
} }
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits) { void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
int init_arrays) {
p->palette_code_bits_ = palette_code_bits; p->palette_code_bits_ = palette_code_bits;
HistogramClear(p); if (init_arrays) {
HistogramClear(p);
} else {
p->trivial_symbol_ = 0;
p->bit_cost_ = 0.;
p->literal_cost_ = 0.;
p->red_cost_ = 0.;
p->blue_cost_ = 0.;
memset(p->is_used_, 0, sizeof(p->is_used_));
}
} }
VP8LHistogram* VP8LAllocateHistogram(int cache_bits) { VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
@ -106,37 +116,70 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits) {
histo = (VP8LHistogram*)memory; histo = (VP8LHistogram*)memory;
// literal_ won't necessary be aligned. // literal_ won't necessary be aligned.
histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
VP8LHistogramInit(histo, cache_bits); VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0);
return histo; return histo;
} }
// Resets the pointers of the histograms to point to the bit buffer in the set.
static void HistogramSetResetPointers(VP8LHistogramSet* const set,
int cache_bits) {
int i;
const int histo_size = VP8LGetHistogramSize(cache_bits);
uint8_t* memory = (uint8_t*) (set->histograms);
memory += set->max_size * sizeof(*set->histograms);
for (i = 0; i < set->max_size; ++i) {
memory = (uint8_t*) WEBP_ALIGN(memory);
set->histograms[i] = (VP8LHistogram*) memory;
// literal_ won't necessary be aligned.
set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
memory += histo_size;
}
}
// Returns the total size of the VP8LHistogramSet.
static size_t HistogramSetTotalSize(int size, int cache_bits) {
const int histo_size = VP8LGetHistogramSize(cache_bits);
return (sizeof(VP8LHistogramSet) + size * (sizeof(VP8LHistogram*) +
histo_size + WEBP_ALIGN_CST));
}
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) { VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits) {
int i; int i;
VP8LHistogramSet* set; VP8LHistogramSet* set;
const int histo_size = VP8LGetHistogramSize(cache_bits); const size_t total_size = HistogramSetTotalSize(size, cache_bits);
const size_t total_size =
sizeof(*set) + size * (sizeof(*set->histograms) +
histo_size + WEBP_ALIGN_CST);
uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory));
if (memory == NULL) return NULL; if (memory == NULL) return NULL;
set = (VP8LHistogramSet*)memory; set = (VP8LHistogramSet*)memory;
memory += sizeof(*set); memory += sizeof(*set);
set->histograms = (VP8LHistogram**)memory; set->histograms = (VP8LHistogram**)memory;
memory += size * sizeof(*set->histograms);
set->max_size = size; set->max_size = size;
set->size = size; set->size = size;
HistogramSetResetPointers(set, cache_bits);
for (i = 0; i < size; ++i) { for (i = 0; i < size; ++i) {
memory = (uint8_t*)WEBP_ALIGN(memory); VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0);
set->histograms[i] = (VP8LHistogram*)memory;
// literal_ won't necessary be aligned.
set->histograms[i]->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram));
VP8LHistogramInit(set->histograms[i], cache_bits);
memory += histo_size;
} }
return set; return set;
} }
void VP8LHistogramSetClear(VP8LHistogramSet* const set) {
int i;
const int cache_bits = set->histograms[0]->palette_code_bits_;
const int size = set->size;
const size_t total_size = HistogramSetTotalSize(size, cache_bits);
uint8_t* memory = (uint8_t*)set;
memset(memory, 0, total_size);
memory += sizeof(*set);
set->histograms = (VP8LHistogram**)memory;
set->max_size = size;
set->size = size;
HistogramSetResetPointers(set, cache_bits);
for (i = 0; i < size; ++i) {
set->histograms[i]->palette_code_bits_ = cache_bits;
}
}
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo, void VP8LHistogramAddSinglePixOrCopy(VP8LHistogram* const histo,
@ -503,6 +546,7 @@ static void HistogramBuild(
VP8LHistogram** const histograms = image_histo->histograms; VP8LHistogram** const histograms = image_histo->histograms;
VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs);
assert(histo_bits > 0); assert(histo_bits > 0);
VP8LHistogramSetClear(image_histo);
while (VP8LRefsCursorOk(&c)) { while (VP8LRefsCursorOk(&c)) {
const PixOrCopy* const v = c.cur_pos; const PixOrCopy* const v = c.cur_pos;
const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits); const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits);

View File

@ -68,7 +68,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p,
int VP8LGetHistogramSize(int palette_code_bits); int VP8LGetHistogramSize(int palette_code_bits);
// Set the palette_code_bits and reset the stats. // Set the palette_code_bits and reset the stats.
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits); // If init_arrays is true, the arrays are also filled with 0's.
void VP8LHistogramInit(VP8LHistogram* const p, int palette_code_bits,
int init_arrays);
// Collect all the references into a histogram (without reset) // Collect all the references into a histogram (without reset)
void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs, void VP8LHistogramStoreRefs(const VP8LBackwardRefs* const refs,
@ -84,6 +86,9 @@ void VP8LFreeHistogramSet(VP8LHistogramSet* const histo);
// using 'cache_bits'. Return NULL in case of memory error. // using 'cache_bits'. Return NULL in case of memory error.
VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits); VP8LHistogramSet* VP8LAllocateHistogramSet(int size, int cache_bits);
// Set the histograms in set to 0.
void VP8LHistogramSetClear(VP8LHistogramSet* const set);
// Allocate and initialize histogram object with specified 'cache_bits'. // Allocate and initialize histogram object with specified 'cache_bits'.
// Returns NULL in case of memory error. // Returns NULL in case of memory error.
// Special case of VP8LAllocateHistogramSet, with size equals 1. // Special case of VP8LAllocateHistogramSet, with size equals 1.

View File

@ -809,6 +809,7 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw,
err = VP8_ENC_ERROR_OUT_OF_MEMORY; err = VP8_ENC_ERROR_OUT_OF_MEMORY;
goto Error; goto Error;
} }
VP8LHistogramSetClear(histogram_image);
// Build histogram image and symbols from backward references. // Build histogram image and symbols from backward references.
VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]); VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);