From d61385db3540b391fdb8f887d25b33232263387e Mon Sep 17 00:00:00 2001 From: Vincent Rabaud Date: Tue, 30 Oct 2018 20:33:20 +0100 Subject: [PATCH] Speed-up: Make sure we only initialize histograms when needed. Also, histograms in a HistogramSet can be initialized all at once. Change-Id: Ibbfa6034dce58dca8bb9113487e2ae507222ce7d (cherry picked from commit 6752904b2f57aa19e325f773e81ac70b4f302f26) --- src/enc/backward_references_cost_enc.c | 2 +- src/enc/backward_references_enc.c | 1 + src/enc/histogram_enc.c | 72 +++++++++++++++++++++----- src/enc/histogram_enc.h | 7 ++- src/enc/vp8l_enc.c | 1 + 5 files changed, 67 insertions(+), 16 deletions(-) diff --git a/src/enc/backward_references_cost_enc.c b/src/enc/backward_references_cost_enc.c index 7175496c..516abd73 100644 --- a/src/enc/backward_references_cost_enc.c +++ b/src/enc/backward_references_cost_enc.c @@ -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 // distance to plane code. - VP8LHistogramInit(histo, cache_bits); + VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 1); while (VP8LRefsCursorOk(&c)) { VP8LHistogramAddSinglePixOrCopy(histo, c.cur_pos, VP8LDistanceToPlaneCode, xsize); diff --git a/src/enc/backward_references_enc.c b/src/enc/backward_references_enc.c index 39230188..3ab7b0ac 100644 --- a/src/enc/backward_references_enc.c +++ b/src/enc/backward_references_enc.c @@ -715,6 +715,7 @@ static int CalculateBestCacheSize(const uint32_t* argb, int quality, for (i = 0; i <= cache_bits_max; ++i) { histos[i] = VP8LAllocateHistogram(i); if (histos[i] == NULL) goto Error; + VP8LHistogramInit(histos[i], i, /*init_arrays=*/ 1); if (i == 0) continue; cc_init[i] = VP8LColorCacheInit(&hashers[i], i); if (!cc_init[i]) goto Error; diff --git a/src/enc/histogram_enc.c b/src/enc/histogram_enc.c index c988b4d4..28a3e6e6 100644 --- a/src/enc/histogram_enc.c +++ b/src/enc/histogram_enc.c @@ -93,9 +93,19 @@ void VP8LHistogramCreate(VP8LHistogram* const 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; - 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) { @@ -106,37 +116,70 @@ VP8LHistogram* VP8LAllocateHistogram(int cache_bits) { histo = (VP8LHistogram*)memory; // literal_ won't necessary be aligned. histo->literal_ = (uint32_t*)(memory + sizeof(VP8LHistogram)); - VP8LHistogramInit(histo, cache_bits); + VP8LHistogramInit(histo, cache_bits, /*init_arrays=*/ 0); 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) { int i; VP8LHistogramSet* set; - const int histo_size = VP8LGetHistogramSize(cache_bits); - const size_t total_size = - sizeof(*set) + size * (sizeof(*set->histograms) + - histo_size + WEBP_ALIGN_CST); + const size_t total_size = HistogramSetTotalSize(size, cache_bits); uint8_t* memory = (uint8_t*)WebPSafeMalloc(total_size, sizeof(*memory)); if (memory == NULL) return NULL; set = (VP8LHistogramSet*)memory; memory += sizeof(*set); set->histograms = (VP8LHistogram**)memory; - memory += size * sizeof(*set->histograms); set->max_size = size; set->size = size; + HistogramSetResetPointers(set, cache_bits); for (i = 0; i < 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)); - VP8LHistogramInit(set->histograms[i], cache_bits); - memory += histo_size; + VP8LHistogramInit(set->histograms[i], cache_bits, /*init_arrays=*/ 0); } 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, @@ -503,6 +546,7 @@ static void HistogramBuild( VP8LHistogram** const histograms = image_histo->histograms; VP8LRefsCursor c = VP8LRefsCursorInit(backward_refs); assert(histo_bits > 0); + VP8LHistogramSetClear(image_histo); while (VP8LRefsCursorOk(&c)) { const PixOrCopy* const v = c.cur_pos; const int ix = (y >> histo_bits) * histo_xsize + (x >> histo_bits); diff --git a/src/enc/histogram_enc.h b/src/enc/histogram_enc.h index 67d82533..54c2d217 100644 --- a/src/enc/histogram_enc.h +++ b/src/enc/histogram_enc.h @@ -68,7 +68,9 @@ void VP8LHistogramCreate(VP8LHistogram* const p, int VP8LGetHistogramSize(int palette_code_bits); // 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) 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. 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'. // Returns NULL in case of memory error. // Special case of VP8LAllocateHistogramSet, with size equals 1. diff --git a/src/enc/vp8l_enc.c b/src/enc/vp8l_enc.c index b7411bf4..2713edcd 100644 --- a/src/enc/vp8l_enc.c +++ b/src/enc/vp8l_enc.c @@ -809,6 +809,7 @@ static WebPEncodingError EncodeImageNoHuffman(VP8LBitWriter* const bw, err = VP8_ENC_ERROR_OUT_OF_MEMORY; goto Error; } + VP8LHistogramSetClear(histogram_image); // Build histogram image and symbols from backward references. VP8LHistogramStoreRefs(refs, histogram_image->histograms[0]);