1 /* Copyright 2015 Google Inc. All Rights Reserved.
2
3 Distributed under MIT license.
4 See file LICENSE for detail or copy at https://opensource.org/licenses/MIT
5 */
6
7 /* Algorithms for distributing the literals and commands of a metablock between
8 block types and contexts. */
9
10 #include "metablock.h"
11
12 #include <brotli/types.h>
13
14 #include "../common/constants.h"
15 #include "../common/context.h"
16 #include "../common/platform.h"
17 #include "bit_cost.h"
18 #include "block_splitter.h"
19 #include "cluster.h"
20 #include "entropy_encode.h"
21 #include "histogram.h"
22 #include "memory.h"
23 #include "quality.h"
24
25 #if defined(__cplusplus) || defined(c_plusplus)
26 extern "C" {
27 #endif
28
BrotliInitDistanceParams(BrotliDistanceParams * dist_params,uint32_t npostfix,uint32_t ndirect,BROTLI_BOOL large_window)29 void BrotliInitDistanceParams(BrotliDistanceParams* dist_params,
30 uint32_t npostfix, uint32_t ndirect, BROTLI_BOOL large_window) {
31 uint32_t alphabet_size_max;
32 uint32_t alphabet_size_limit;
33 uint32_t max_distance;
34
35 dist_params->distance_postfix_bits = npostfix;
36 dist_params->num_direct_distance_codes = ndirect;
37
38 alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
39 npostfix, ndirect, BROTLI_MAX_DISTANCE_BITS);
40 alphabet_size_limit = alphabet_size_max;
41 max_distance = ndirect + (1U << (BROTLI_MAX_DISTANCE_BITS + npostfix + 2)) -
42 (1U << (npostfix + 2));
43
44 if (large_window) {
45 BrotliDistanceCodeLimit limit = BrotliCalculateDistanceCodeLimit(
46 BROTLI_MAX_ALLOWED_DISTANCE, npostfix, ndirect);
47 alphabet_size_max = BROTLI_DISTANCE_ALPHABET_SIZE(
48 npostfix, ndirect, BROTLI_LARGE_MAX_DISTANCE_BITS);
49 alphabet_size_limit = limit.max_alphabet_size;
50 max_distance = limit.max_distance;
51 }
52
53 dist_params->alphabet_size_max = alphabet_size_max;
54 dist_params->alphabet_size_limit = alphabet_size_limit;
55 dist_params->max_distance = max_distance;
56 }
57
RecomputeDistancePrefixes(Command * cmds,size_t num_commands,const BrotliDistanceParams * orig_params,const BrotliDistanceParams * new_params)58 static void RecomputeDistancePrefixes(Command* cmds,
59 size_t num_commands,
60 const BrotliDistanceParams* orig_params,
61 const BrotliDistanceParams* new_params) {
62 size_t i;
63
64 if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
65 orig_params->num_direct_distance_codes ==
66 new_params->num_direct_distance_codes) {
67 return;
68 }
69
70 for (i = 0; i < num_commands; ++i) {
71 Command* cmd = &cmds[i];
72 if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
73 PrefixEncodeCopyDistance(CommandRestoreDistanceCode(cmd, orig_params),
74 new_params->num_direct_distance_codes,
75 new_params->distance_postfix_bits,
76 &cmd->dist_prefix_,
77 &cmd->dist_extra_);
78 }
79 }
80 }
81
ComputeDistanceCost(const Command * cmds,size_t num_commands,const BrotliDistanceParams * orig_params,const BrotliDistanceParams * new_params,double * cost,HistogramDistance * tmp)82 static BROTLI_BOOL ComputeDistanceCost(const Command* cmds,
83 size_t num_commands,
84 const BrotliDistanceParams* orig_params,
85 const BrotliDistanceParams* new_params,
86 double* cost,
87 HistogramDistance* tmp) {
88 size_t i;
89 BROTLI_BOOL equal_params = BROTLI_FALSE;
90 uint16_t dist_prefix;
91 uint32_t dist_extra;
92 double extra_bits = 0.0;
93 HistogramClearDistance(tmp);
94
95 if (orig_params->distance_postfix_bits == new_params->distance_postfix_bits &&
96 orig_params->num_direct_distance_codes ==
97 new_params->num_direct_distance_codes) {
98 equal_params = BROTLI_TRUE;
99 }
100
101 for (i = 0; i < num_commands; i++) {
102 const Command* cmd = &cmds[i];
103 if (CommandCopyLen(cmd) && cmd->cmd_prefix_ >= 128) {
104 if (equal_params) {
105 dist_prefix = cmd->dist_prefix_;
106 } else {
107 uint32_t distance = CommandRestoreDistanceCode(cmd, orig_params);
108 if (distance > new_params->max_distance) {
109 return BROTLI_FALSE;
110 }
111 PrefixEncodeCopyDistance(distance,
112 new_params->num_direct_distance_codes,
113 new_params->distance_postfix_bits,
114 &dist_prefix,
115 &dist_extra);
116 }
117 HistogramAddDistance(tmp, dist_prefix & 0x3FF);
118 extra_bits += dist_prefix >> 10;
119 }
120 }
121
122 *cost = BrotliPopulationCostDistance(tmp) + extra_bits;
123 return BROTLI_TRUE;
124 }
125
BrotliBuildMetaBlock(MemoryManager * m,const uint8_t * ringbuffer,const size_t pos,const size_t mask,BrotliEncoderParams * params,uint8_t prev_byte,uint8_t prev_byte2,Command * cmds,size_t num_commands,ContextType literal_context_mode,MetaBlockSplit * mb)126 void BrotliBuildMetaBlock(MemoryManager* m,
127 const uint8_t* ringbuffer,
128 const size_t pos,
129 const size_t mask,
130 BrotliEncoderParams* params,
131 uint8_t prev_byte,
132 uint8_t prev_byte2,
133 Command* cmds,
134 size_t num_commands,
135 ContextType literal_context_mode,
136 MetaBlockSplit* mb) {
137 /* Histogram ids need to fit in one byte. */
138 static const size_t kMaxNumberOfHistograms = 256;
139 HistogramDistance* distance_histograms;
140 HistogramLiteral* literal_histograms;
141 ContextType* literal_context_modes = NULL;
142 size_t literal_histograms_size;
143 size_t distance_histograms_size;
144 size_t i;
145 size_t literal_context_multiplier = 1;
146 uint32_t npostfix;
147 uint32_t ndirect_msb = 0;
148 BROTLI_BOOL check_orig = BROTLI_TRUE;
149 double best_dist_cost = 1e99;
150 BrotliDistanceParams orig_params = params->dist;
151 BrotliDistanceParams new_params = params->dist;
152 HistogramDistance* tmp = BROTLI_ALLOC(m, HistogramDistance, 1);
153
154 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(tmp)) return;
155
156 for (npostfix = 0; npostfix <= BROTLI_MAX_NPOSTFIX; npostfix++) {
157 for (; ndirect_msb < 16; ndirect_msb++) {
158 uint32_t ndirect = ndirect_msb << npostfix;
159 BROTLI_BOOL skip;
160 double dist_cost;
161 BrotliInitDistanceParams(&new_params, npostfix, ndirect,
162 params->large_window);
163 if (npostfix == orig_params.distance_postfix_bits &&
164 ndirect == orig_params.num_direct_distance_codes) {
165 check_orig = BROTLI_FALSE;
166 }
167 skip = !ComputeDistanceCost(
168 cmds, num_commands, &orig_params, &new_params, &dist_cost, tmp);
169 if (skip || (dist_cost > best_dist_cost)) {
170 break;
171 }
172 best_dist_cost = dist_cost;
173 params->dist = new_params;
174 }
175 if (ndirect_msb > 0) ndirect_msb--;
176 ndirect_msb /= 2;
177 }
178 if (check_orig) {
179 double dist_cost;
180 ComputeDistanceCost(cmds, num_commands, &orig_params, &orig_params,
181 &dist_cost, tmp);
182 if (dist_cost < best_dist_cost) {
183 /* NB: currently unused; uncomment when more param tuning is added. */
184 /* best_dist_cost = dist_cost; */
185 params->dist = orig_params;
186 }
187 }
188 BROTLI_FREE(m, tmp);
189 RecomputeDistancePrefixes(cmds, num_commands, &orig_params, ¶ms->dist);
190
191 BrotliSplitBlock(m, cmds, num_commands,
192 ringbuffer, pos, mask, params,
193 &mb->literal_split,
194 &mb->command_split,
195 &mb->distance_split);
196 if (BROTLI_IS_OOM(m)) return;
197
198 if (!params->disable_literal_context_modeling) {
199 literal_context_multiplier = 1 << BROTLI_LITERAL_CONTEXT_BITS;
200 literal_context_modes =
201 BROTLI_ALLOC(m, ContextType, mb->literal_split.num_types);
202 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_context_modes)) return;
203 for (i = 0; i < mb->literal_split.num_types; ++i) {
204 literal_context_modes[i] = literal_context_mode;
205 }
206 }
207
208 literal_histograms_size =
209 mb->literal_split.num_types * literal_context_multiplier;
210 literal_histograms =
211 BROTLI_ALLOC(m, HistogramLiteral, literal_histograms_size);
212 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(literal_histograms)) return;
213 ClearHistogramsLiteral(literal_histograms, literal_histograms_size);
214
215 distance_histograms_size =
216 mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
217 distance_histograms =
218 BROTLI_ALLOC(m, HistogramDistance, distance_histograms_size);
219 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(distance_histograms)) return;
220 ClearHistogramsDistance(distance_histograms, distance_histograms_size);
221
222 BROTLI_DCHECK(mb->command_histograms == 0);
223 mb->command_histograms_size = mb->command_split.num_types;
224 mb->command_histograms =
225 BROTLI_ALLOC(m, HistogramCommand, mb->command_histograms_size);
226 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->command_histograms)) return;
227 ClearHistogramsCommand(mb->command_histograms, mb->command_histograms_size);
228
229 BrotliBuildHistogramsWithContext(cmds, num_commands,
230 &mb->literal_split, &mb->command_split, &mb->distance_split,
231 ringbuffer, pos, mask, prev_byte, prev_byte2, literal_context_modes,
232 literal_histograms, mb->command_histograms, distance_histograms);
233 BROTLI_FREE(m, literal_context_modes);
234
235 BROTLI_DCHECK(mb->literal_context_map == 0);
236 mb->literal_context_map_size =
237 mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
238 mb->literal_context_map =
239 BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
240 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
241
242 BROTLI_DCHECK(mb->literal_histograms == 0);
243 mb->literal_histograms_size = mb->literal_context_map_size;
244 mb->literal_histograms =
245 BROTLI_ALLOC(m, HistogramLiteral, mb->literal_histograms_size);
246 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_histograms)) return;
247
248 BrotliClusterHistogramsLiteral(m, literal_histograms, literal_histograms_size,
249 kMaxNumberOfHistograms, mb->literal_histograms,
250 &mb->literal_histograms_size, mb->literal_context_map);
251 if (BROTLI_IS_OOM(m)) return;
252 BROTLI_FREE(m, literal_histograms);
253
254 if (params->disable_literal_context_modeling) {
255 /* Distribute assignment to all contexts. */
256 for (i = mb->literal_split.num_types; i != 0;) {
257 size_t j = 0;
258 i--;
259 for (; j < (1 << BROTLI_LITERAL_CONTEXT_BITS); j++) {
260 mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
261 mb->literal_context_map[i];
262 }
263 }
264 }
265
266 BROTLI_DCHECK(mb->distance_context_map == 0);
267 mb->distance_context_map_size =
268 mb->distance_split.num_types << BROTLI_DISTANCE_CONTEXT_BITS;
269 mb->distance_context_map =
270 BROTLI_ALLOC(m, uint32_t, mb->distance_context_map_size);
271 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_context_map)) return;
272
273 BROTLI_DCHECK(mb->distance_histograms == 0);
274 mb->distance_histograms_size = mb->distance_context_map_size;
275 mb->distance_histograms =
276 BROTLI_ALLOC(m, HistogramDistance, mb->distance_histograms_size);
277 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->distance_histograms)) return;
278
279 BrotliClusterHistogramsDistance(m, distance_histograms,
280 mb->distance_context_map_size,
281 kMaxNumberOfHistograms,
282 mb->distance_histograms,
283 &mb->distance_histograms_size,
284 mb->distance_context_map);
285 if (BROTLI_IS_OOM(m)) return;
286 BROTLI_FREE(m, distance_histograms);
287 }
288
289 #define FN(X) X ## Literal
290 #include "metablock_inc.h" /* NOLINT(build/include) */
291 #undef FN
292
293 #define FN(X) X ## Command
294 #include "metablock_inc.h" /* NOLINT(build/include) */
295 #undef FN
296
297 #define FN(X) X ## Distance
298 #include "metablock_inc.h" /* NOLINT(build/include) */
299 #undef FN
300
301 #define BROTLI_MAX_STATIC_CONTEXTS 13
302
303 /* Greedy block splitter for one block category (literal, command or distance).
304 Gathers histograms for all context buckets. */
305 typedef struct ContextBlockSplitter {
306 /* Alphabet size of particular block category. */
307 size_t alphabet_size_;
308 size_t num_contexts_;
309 size_t max_block_types_;
310 /* We collect at least this many symbols for each block. */
311 size_t min_block_size_;
312 /* We merge histograms A and B if
313 entropy(A+B) < entropy(A) + entropy(B) + split_threshold_,
314 where A is the current histogram and B is the histogram of the last or the
315 second last block type. */
316 double split_threshold_;
317
318 size_t num_blocks_;
319 BlockSplit* split_; /* not owned */
320 HistogramLiteral* histograms_; /* not owned */
321 size_t* histograms_size_; /* not owned */
322
323 /* The number of symbols that we want to collect before deciding on whether
324 or not to merge the block with a previous one or emit a new block. */
325 size_t target_block_size_;
326 /* The number of symbols in the current histogram. */
327 size_t block_size_;
328 /* Offset of the current histogram. */
329 size_t curr_histogram_ix_;
330 /* Offset of the histograms of the previous two block types. */
331 size_t last_histogram_ix_[2];
332 /* Entropy of the previous two block types. */
333 double last_entropy_[2 * BROTLI_MAX_STATIC_CONTEXTS];
334 /* The number of times we merged the current block with the last one. */
335 size_t merge_last_count_;
336 } ContextBlockSplitter;
337
InitContextBlockSplitter(MemoryManager * m,ContextBlockSplitter * self,size_t alphabet_size,size_t num_contexts,size_t min_block_size,double split_threshold,size_t num_symbols,BlockSplit * split,HistogramLiteral ** histograms,size_t * histograms_size)338 static void InitContextBlockSplitter(
339 MemoryManager* m, ContextBlockSplitter* self, size_t alphabet_size,
340 size_t num_contexts, size_t min_block_size, double split_threshold,
341 size_t num_symbols, BlockSplit* split, HistogramLiteral** histograms,
342 size_t* histograms_size) {
343 size_t max_num_blocks = num_symbols / min_block_size + 1;
344 size_t max_num_types;
345 BROTLI_DCHECK(num_contexts <= BROTLI_MAX_STATIC_CONTEXTS);
346
347 self->alphabet_size_ = alphabet_size;
348 self->num_contexts_ = num_contexts;
349 self->max_block_types_ = BROTLI_MAX_NUMBER_OF_BLOCK_TYPES / num_contexts;
350 self->min_block_size_ = min_block_size;
351 self->split_threshold_ = split_threshold;
352 self->num_blocks_ = 0;
353 self->split_ = split;
354 self->histograms_size_ = histograms_size;
355 self->target_block_size_ = min_block_size;
356 self->block_size_ = 0;
357 self->curr_histogram_ix_ = 0;
358 self->merge_last_count_ = 0;
359
360 /* We have to allocate one more histogram than the maximum number of block
361 types for the current histogram when the meta-block is too big. */
362 max_num_types =
363 BROTLI_MIN(size_t, max_num_blocks, self->max_block_types_ + 1);
364 BROTLI_ENSURE_CAPACITY(m, uint8_t,
365 split->types, split->types_alloc_size, max_num_blocks);
366 BROTLI_ENSURE_CAPACITY(m, uint32_t,
367 split->lengths, split->lengths_alloc_size, max_num_blocks);
368 if (BROTLI_IS_OOM(m)) return;
369 split->num_blocks = max_num_blocks;
370 if (BROTLI_IS_OOM(m)) return;
371 BROTLI_DCHECK(*histograms == 0);
372 *histograms_size = max_num_types * num_contexts;
373 *histograms = BROTLI_ALLOC(m, HistogramLiteral, *histograms_size);
374 self->histograms_ = *histograms;
375 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(*histograms)) return;
376 /* Clear only current histogram. */
377 ClearHistogramsLiteral(&self->histograms_[0], num_contexts);
378 self->last_histogram_ix_[0] = self->last_histogram_ix_[1] = 0;
379 }
380
381 /* Does either of three things:
382 (1) emits the current block with a new block type;
383 (2) emits the current block with the type of the second last block;
384 (3) merges the current block with the last block. */
ContextBlockSplitterFinishBlock(ContextBlockSplitter * self,MemoryManager * m,BROTLI_BOOL is_final)385 static void ContextBlockSplitterFinishBlock(
386 ContextBlockSplitter* self, MemoryManager* m, BROTLI_BOOL is_final) {
387 BlockSplit* split = self->split_;
388 const size_t num_contexts = self->num_contexts_;
389 double* last_entropy = self->last_entropy_;
390 HistogramLiteral* histograms = self->histograms_;
391
392 if (self->block_size_ < self->min_block_size_) {
393 self->block_size_ = self->min_block_size_;
394 }
395 if (self->num_blocks_ == 0) {
396 size_t i;
397 /* Create first block. */
398 split->lengths[0] = (uint32_t)self->block_size_;
399 split->types[0] = 0;
400
401 for (i = 0; i < num_contexts; ++i) {
402 last_entropy[i] =
403 BitsEntropy(histograms[i].data_, self->alphabet_size_);
404 last_entropy[num_contexts + i] = last_entropy[i];
405 }
406 ++self->num_blocks_;
407 ++split->num_types;
408 self->curr_histogram_ix_ += num_contexts;
409 if (self->curr_histogram_ix_ < *self->histograms_size_) {
410 ClearHistogramsLiteral(
411 &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
412 }
413 self->block_size_ = 0;
414 } else if (self->block_size_ > 0) {
415 /* Try merging the set of histograms for the current block type with the
416 respective set of histograms for the last and second last block types.
417 Decide over the split based on the total reduction of entropy across
418 all contexts. */
419 double entropy[BROTLI_MAX_STATIC_CONTEXTS];
420 HistogramLiteral* combined_histo =
421 BROTLI_ALLOC(m, HistogramLiteral, 2 * num_contexts);
422 double combined_entropy[2 * BROTLI_MAX_STATIC_CONTEXTS];
423 double diff[2] = { 0.0 };
424 size_t i;
425 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(combined_histo)) return;
426 for (i = 0; i < num_contexts; ++i) {
427 size_t curr_histo_ix = self->curr_histogram_ix_ + i;
428 size_t j;
429 entropy[i] = BitsEntropy(histograms[curr_histo_ix].data_,
430 self->alphabet_size_);
431 for (j = 0; j < 2; ++j) {
432 size_t jx = j * num_contexts + i;
433 size_t last_histogram_ix = self->last_histogram_ix_[j] + i;
434 combined_histo[jx] = histograms[curr_histo_ix];
435 HistogramAddHistogramLiteral(&combined_histo[jx],
436 &histograms[last_histogram_ix]);
437 combined_entropy[jx] = BitsEntropy(
438 &combined_histo[jx].data_[0], self->alphabet_size_);
439 diff[j] += combined_entropy[jx] - entropy[i] - last_entropy[jx];
440 }
441 }
442
443 if (split->num_types < self->max_block_types_ &&
444 diff[0] > self->split_threshold_ &&
445 diff[1] > self->split_threshold_) {
446 /* Create new block. */
447 split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
448 split->types[self->num_blocks_] = (uint8_t)split->num_types;
449 self->last_histogram_ix_[1] = self->last_histogram_ix_[0];
450 self->last_histogram_ix_[0] = split->num_types * num_contexts;
451 for (i = 0; i < num_contexts; ++i) {
452 last_entropy[num_contexts + i] = last_entropy[i];
453 last_entropy[i] = entropy[i];
454 }
455 ++self->num_blocks_;
456 ++split->num_types;
457 self->curr_histogram_ix_ += num_contexts;
458 if (self->curr_histogram_ix_ < *self->histograms_size_) {
459 ClearHistogramsLiteral(
460 &self->histograms_[self->curr_histogram_ix_], self->num_contexts_);
461 }
462 self->block_size_ = 0;
463 self->merge_last_count_ = 0;
464 self->target_block_size_ = self->min_block_size_;
465 } else if (diff[1] < diff[0] - 20.0) {
466 /* Combine this block with second last block. */
467 split->lengths[self->num_blocks_] = (uint32_t)self->block_size_;
468 split->types[self->num_blocks_] = split->types[self->num_blocks_ - 2];
469 BROTLI_SWAP(size_t, self->last_histogram_ix_, 0, 1);
470 for (i = 0; i < num_contexts; ++i) {
471 histograms[self->last_histogram_ix_[0] + i] =
472 combined_histo[num_contexts + i];
473 last_entropy[num_contexts + i] = last_entropy[i];
474 last_entropy[i] = combined_entropy[num_contexts + i];
475 HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
476 }
477 ++self->num_blocks_;
478 self->block_size_ = 0;
479 self->merge_last_count_ = 0;
480 self->target_block_size_ = self->min_block_size_;
481 } else {
482 /* Combine this block with last block. */
483 split->lengths[self->num_blocks_ - 1] += (uint32_t)self->block_size_;
484 for (i = 0; i < num_contexts; ++i) {
485 histograms[self->last_histogram_ix_[0] + i] = combined_histo[i];
486 last_entropy[i] = combined_entropy[i];
487 if (split->num_types == 1) {
488 last_entropy[num_contexts + i] = last_entropy[i];
489 }
490 HistogramClearLiteral(&histograms[self->curr_histogram_ix_ + i]);
491 }
492 self->block_size_ = 0;
493 if (++self->merge_last_count_ > 1) {
494 self->target_block_size_ += self->min_block_size_;
495 }
496 }
497 BROTLI_FREE(m, combined_histo);
498 }
499 if (is_final) {
500 *self->histograms_size_ = split->num_types * num_contexts;
501 split->num_blocks = self->num_blocks_;
502 }
503 }
504
505 /* Adds the next symbol to the current block type and context. When the
506 current block reaches the target size, decides on merging the block. */
ContextBlockSplitterAddSymbol(ContextBlockSplitter * self,MemoryManager * m,size_t symbol,size_t context)507 static void ContextBlockSplitterAddSymbol(
508 ContextBlockSplitter* self, MemoryManager* m,
509 size_t symbol, size_t context) {
510 HistogramAddLiteral(&self->histograms_[self->curr_histogram_ix_ + context],
511 symbol);
512 ++self->block_size_;
513 if (self->block_size_ == self->target_block_size_) {
514 ContextBlockSplitterFinishBlock(self, m, /* is_final = */ BROTLI_FALSE);
515 if (BROTLI_IS_OOM(m)) return;
516 }
517 }
518
MapStaticContexts(MemoryManager * m,size_t num_contexts,const uint32_t * static_context_map,MetaBlockSplit * mb)519 static void MapStaticContexts(MemoryManager* m,
520 size_t num_contexts,
521 const uint32_t* static_context_map,
522 MetaBlockSplit* mb) {
523 size_t i;
524 BROTLI_DCHECK(mb->literal_context_map == 0);
525 mb->literal_context_map_size =
526 mb->literal_split.num_types << BROTLI_LITERAL_CONTEXT_BITS;
527 mb->literal_context_map =
528 BROTLI_ALLOC(m, uint32_t, mb->literal_context_map_size);
529 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(mb->literal_context_map)) return;
530
531 for (i = 0; i < mb->literal_split.num_types; ++i) {
532 uint32_t offset = (uint32_t)(i * num_contexts);
533 size_t j;
534 for (j = 0; j < (1u << BROTLI_LITERAL_CONTEXT_BITS); ++j) {
535 mb->literal_context_map[(i << BROTLI_LITERAL_CONTEXT_BITS) + j] =
536 offset + static_context_map[j];
537 }
538 }
539 }
540
541 typedef struct GreedyMetablockArena {
542 union {
543 BlockSplitterLiteral plain;
544 ContextBlockSplitter ctx;
545 } lit_blocks;
546 BlockSplitterCommand cmd_blocks;
547 BlockSplitterDistance dist_blocks;
548 } GreedyMetablockArena;
549
BrotliBuildMetaBlockGreedyInternal(MemoryManager * m,GreedyMetablockArena * arena,const uint8_t * ringbuffer,size_t pos,size_t mask,uint8_t prev_byte,uint8_t prev_byte2,ContextLut literal_context_lut,const size_t num_contexts,const uint32_t * static_context_map,const Command * commands,size_t n_commands,MetaBlockSplit * mb)550 static BROTLI_INLINE void BrotliBuildMetaBlockGreedyInternal(
551 MemoryManager* m, GreedyMetablockArena* arena, const uint8_t* ringbuffer,
552 size_t pos, size_t mask, uint8_t prev_byte, uint8_t prev_byte2,
553 ContextLut literal_context_lut, const size_t num_contexts,
554 const uint32_t* static_context_map, const Command* commands,
555 size_t n_commands, MetaBlockSplit* mb) {
556 size_t num_literals = 0;
557 size_t i;
558 for (i = 0; i < n_commands; ++i) {
559 num_literals += commands[i].insert_len_;
560 }
561
562 if (num_contexts == 1) {
563 InitBlockSplitterLiteral(m, &arena->lit_blocks.plain, 256, 512, 400.0,
564 num_literals, &mb->literal_split, &mb->literal_histograms,
565 &mb->literal_histograms_size);
566 } else {
567 InitContextBlockSplitter(m, &arena->lit_blocks.ctx, 256, num_contexts, 512,
568 400.0, num_literals, &mb->literal_split, &mb->literal_histograms,
569 &mb->literal_histograms_size);
570 }
571 if (BROTLI_IS_OOM(m)) return;
572 InitBlockSplitterCommand(m, &arena->cmd_blocks, BROTLI_NUM_COMMAND_SYMBOLS,
573 1024, 500.0, n_commands, &mb->command_split, &mb->command_histograms,
574 &mb->command_histograms_size);
575 if (BROTLI_IS_OOM(m)) return;
576 InitBlockSplitterDistance(m, &arena->dist_blocks, 64, 512, 100.0, n_commands,
577 &mb->distance_split, &mb->distance_histograms,
578 &mb->distance_histograms_size);
579 if (BROTLI_IS_OOM(m)) return;
580
581 for (i = 0; i < n_commands; ++i) {
582 const Command cmd = commands[i];
583 size_t j;
584 BlockSplitterAddSymbolCommand(&arena->cmd_blocks, cmd.cmd_prefix_);
585 for (j = cmd.insert_len_; j != 0; --j) {
586 uint8_t literal = ringbuffer[pos & mask];
587 if (num_contexts == 1) {
588 BlockSplitterAddSymbolLiteral(&arena->lit_blocks.plain, literal);
589 } else {
590 size_t context =
591 BROTLI_CONTEXT(prev_byte, prev_byte2, literal_context_lut);
592 ContextBlockSplitterAddSymbol(&arena->lit_blocks.ctx, m, literal,
593 static_context_map[context]);
594 if (BROTLI_IS_OOM(m)) return;
595 }
596 prev_byte2 = prev_byte;
597 prev_byte = literal;
598 ++pos;
599 }
600 pos += CommandCopyLen(&cmd);
601 if (CommandCopyLen(&cmd)) {
602 prev_byte2 = ringbuffer[(pos - 2) & mask];
603 prev_byte = ringbuffer[(pos - 1) & mask];
604 if (cmd.cmd_prefix_ >= 128) {
605 BlockSplitterAddSymbolDistance(
606 &arena->dist_blocks, cmd.dist_prefix_ & 0x3FF);
607 }
608 }
609 }
610
611 if (num_contexts == 1) {
612 BlockSplitterFinishBlockLiteral(
613 &arena->lit_blocks.plain, /* is_final = */ BROTLI_TRUE);
614 } else {
615 ContextBlockSplitterFinishBlock(
616 &arena->lit_blocks.ctx, m, /* is_final = */ BROTLI_TRUE);
617 if (BROTLI_IS_OOM(m)) return;
618 }
619 BlockSplitterFinishBlockCommand(
620 &arena->cmd_blocks, /* is_final = */ BROTLI_TRUE);
621 BlockSplitterFinishBlockDistance(
622 &arena->dist_blocks, /* is_final = */ BROTLI_TRUE);
623
624 if (num_contexts > 1) {
625 MapStaticContexts(m, num_contexts, static_context_map, mb);
626 }
627 }
628
BrotliBuildMetaBlockGreedy(MemoryManager * m,const uint8_t * ringbuffer,size_t pos,size_t mask,uint8_t prev_byte,uint8_t prev_byte2,ContextLut literal_context_lut,size_t num_contexts,const uint32_t * static_context_map,const Command * commands,size_t n_commands,MetaBlockSplit * mb)629 void BrotliBuildMetaBlockGreedy(MemoryManager* m,
630 const uint8_t* ringbuffer,
631 size_t pos,
632 size_t mask,
633 uint8_t prev_byte,
634 uint8_t prev_byte2,
635 ContextLut literal_context_lut,
636 size_t num_contexts,
637 const uint32_t* static_context_map,
638 const Command* commands,
639 size_t n_commands,
640 MetaBlockSplit* mb) {
641 GreedyMetablockArena* arena = BROTLI_ALLOC(m, GreedyMetablockArena, 1);
642 if (BROTLI_IS_OOM(m) || BROTLI_IS_NULL(arena)) return;
643 if (num_contexts == 1) {
644 BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
645 prev_byte, prev_byte2, literal_context_lut, 1, NULL, commands,
646 n_commands, mb);
647 } else {
648 BrotliBuildMetaBlockGreedyInternal(m, arena, ringbuffer, pos, mask,
649 prev_byte, prev_byte2, literal_context_lut, num_contexts,
650 static_context_map, commands, n_commands, mb);
651 }
652 BROTLI_FREE(m, arena);
653 }
654
BrotliOptimizeHistograms(uint32_t num_distance_codes,MetaBlockSplit * mb)655 void BrotliOptimizeHistograms(uint32_t num_distance_codes,
656 MetaBlockSplit* mb) {
657 uint8_t good_for_rle[BROTLI_NUM_COMMAND_SYMBOLS];
658 size_t i;
659 for (i = 0; i < mb->literal_histograms_size; ++i) {
660 BrotliOptimizeHuffmanCountsForRle(256, mb->literal_histograms[i].data_,
661 good_for_rle);
662 }
663 for (i = 0; i < mb->command_histograms_size; ++i) {
664 BrotliOptimizeHuffmanCountsForRle(BROTLI_NUM_COMMAND_SYMBOLS,
665 mb->command_histograms[i].data_,
666 good_for_rle);
667 }
668 for (i = 0; i < mb->distance_histograms_size; ++i) {
669 BrotliOptimizeHuffmanCountsForRle(num_distance_codes,
670 mb->distance_histograms[i].data_,
671 good_for_rle);
672 }
673 }
674
675 #if defined(__cplusplus) || defined(c_plusplus)
676 } /* extern "C" */
677 #endif
678