[subset] Optimize hmtx/vmtx serialization.

Make serializer allocation up front to avoid bounds checking overhead for each metric.

Benchmarks:
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10_median                   -0.1005         -0.1005             0             0             0             0
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/64_median                   -0.0693         -0.0692             0             0             0             0
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/512_median                  -0.0294         -0.0293             1             1             1             1
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/4096_median                 -0.0033         -0.0032             3             3             3             3
BM_subset/subset_glyphs/Mplus1p-Regular.ttf/retaingids/10000_median                +0.0170         +0.0171             7             7             7             7
This commit is contained in:
Garret Rieger 2023-06-02 18:32:09 +00:00 committed by Behdad Esfahbod
parent c6368e014d
commit ad872e2313

View file

@ -158,31 +158,25 @@ struct hmtxvmtx
hb_requires (hb_is_iterator (Iterator))>
void serialize (hb_serialize_context_t *c,
Iterator it,
unsigned num_long_metrics)
unsigned num_long_metrics,
unsigned total_num_metrics)
{
unsigned idx = 0;
LongMetric* long_metrics = c->allocate_size<LongMetric> (num_long_metrics * LongMetric::static_size);
FWORD* short_metrics = c->allocate_size<FWORD> ((total_num_metrics - num_long_metrics) * FWORD::static_size);
if (!long_metrics || !short_metrics) return;
for (auto _ : it)
{
if (idx < num_long_metrics)
{
LongMetric lm;
LongMetric& lm = long_metrics[idx];
lm.advance = _.first;
lm.sb = _.second;
if (unlikely (!c->embed<LongMetric> (&lm))) return;
}
else if (idx < 0x10000u)
{
FWORD *sb = c->allocate_size<FWORD> (FWORD::static_size);
if (unlikely (!sb)) return;
*sb = _.second;
}
*(short_metrics++) = _.second;
else
{
// TODO: This does not do tail optimization.
UFWORD *adv = c->allocate_size<UFWORD> (UFWORD::static_size);
if (unlikely (!adv)) return;
*adv = _.first;
}
*((UFWORD*) short_metrics++) = _.first;
idx++;
}
}
@ -231,7 +225,7 @@ struct hmtxvmtx
})
;
table_prime->serialize (c->serializer, it, num_long_metrics);
table_prime->serialize (c->serializer, it, num_long_metrics, c->plan->new_to_old_gid_list.length);
if (unlikely (c->serializer->in_error ()))
return_trace (false);