[repacker] Add basic version of the extension promotion selection algorithm.
This commit is contained in:
parent
514fcea0aa
commit
8c6afa69d5
|
@ -480,6 +480,18 @@ struct graph_t
|
||||||
find_subgraph (link.objidx, subgraph);
|
find_subgraph (link.objidx, subgraph);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t find_subgraph_size (unsigned node_idx, hb_set_t& subgraph)
|
||||||
|
{
|
||||||
|
if (subgraph.has (node_idx)) return 0;
|
||||||
|
subgraph.add (node_idx);
|
||||||
|
|
||||||
|
const auto& o = vertices_[node_idx].obj;
|
||||||
|
size_t size = o.tail - o.head;
|
||||||
|
for (const auto& link : o.all_links ())
|
||||||
|
size += find_subgraph_size (link.objidx, subgraph);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Finds the topmost children of 32bit offsets in the subgraph starting
|
* Finds the topmost children of 32bit offsets in the subgraph starting
|
||||||
* at node_idx. Found indices are placed into 'found'.
|
* at node_idx. Found indices are placed into 'found'.
|
||||||
|
|
|
@ -41,6 +41,13 @@ using graph::graph_t;
|
||||||
* docs/repacker.md
|
* docs/repacker.md
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
inline int compare_sizes (const void* a, const void* b)
|
||||||
|
{
|
||||||
|
hb_pair_t<unsigned, size_t>* size_a = (hb_pair_t<unsigned, size_t>*) a;
|
||||||
|
hb_pair_t<unsigned, size_t>* size_b = (hb_pair_t<unsigned, size_t>*) b;
|
||||||
|
return size_a->second - size_b->second;
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
|
* Analyze the lookups in a GSUB/GPOS table and decide if any should be promoted
|
||||||
* to extension lookups.
|
* to extension lookups.
|
||||||
|
@ -48,10 +55,44 @@ using graph::graph_t;
|
||||||
static inline
|
static inline
|
||||||
bool _promote_extensions_if_needed (graph::make_extension_context_t& ext_context)
|
bool _promote_extensions_if_needed (graph::make_extension_context_t& ext_context)
|
||||||
{
|
{
|
||||||
// TODO: Move this into graph or gsubgpos graph?
|
// Simple Algorithm (v1, current):
|
||||||
for (auto p : ext_context.lookups.iter ())
|
// 1. Calculate how many bytes each non-extension lookup consumes.
|
||||||
|
// 2. Select up to 64k of those to remain as non-extension (greedy, smallest first).
|
||||||
|
// 3. Promote the rest.
|
||||||
|
//
|
||||||
|
// Advanced Algorithm (v2, not implemented):
|
||||||
|
// 1. Perform connected component analysis using lookups as roots.
|
||||||
|
// 2. Compute size of each connected component.
|
||||||
|
// 3. Select up to 64k worth of connected components to remain as non-extensions.
|
||||||
|
// (greedy, smallest first)
|
||||||
|
// 4. Promote the rest.
|
||||||
|
|
||||||
|
// TODO(garretrieger): support extension demotion, then consider all lookups. Requires advanced algo.
|
||||||
|
|
||||||
|
hb_vector_t<hb_pair_t<unsigned, size_t>> lookup_sizes;
|
||||||
|
lookup_sizes.alloc (ext_context.lookups.get_population ());
|
||||||
|
|
||||||
|
for (unsigned lookup_index : ext_context.lookups.keys ())
|
||||||
{
|
{
|
||||||
if (!p.second->make_extension (ext_context, p.first))
|
hb_set_t visited;
|
||||||
|
lookup_sizes.push (hb_pair_t<unsigned, size_t> {
|
||||||
|
lookup_index,
|
||||||
|
ext_context.graph.find_subgraph_size (lookup_index, visited)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
lookup_sizes.qsort (compare_sizes);
|
||||||
|
|
||||||
|
size_t accumlated_bytes = 0;
|
||||||
|
for (auto p : lookup_sizes)
|
||||||
|
{
|
||||||
|
unsigned lookup_index = p.first;
|
||||||
|
size_t size = p.second;
|
||||||
|
accumlated_bytes += size;
|
||||||
|
|
||||||
|
if (accumlated_bytes < (1 << 16)) continue; // this lookup fits with 64k, which won't overflow.
|
||||||
|
|
||||||
|
if (!ext_context.lookups.get(lookup_index)->make_extension (ext_context, lookup_index))
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -173,7 +214,8 @@ template<typename T>
|
||||||
inline hb_blob_t*
|
inline hb_blob_t*
|
||||||
hb_resolve_overflows (const T& packed,
|
hb_resolve_overflows (const T& packed,
|
||||||
hb_tag_t table_tag,
|
hb_tag_t table_tag,
|
||||||
unsigned max_rounds = 20) {
|
unsigned max_rounds = 20,
|
||||||
|
bool recalculate_extensions = false) {
|
||||||
graph_t sorted_graph (packed);
|
graph_t sorted_graph (packed);
|
||||||
sorted_graph.sort_shortest_distance ();
|
sorted_graph.sort_shortest_distance ();
|
||||||
|
|
||||||
|
@ -188,15 +230,18 @@ hb_resolve_overflows (const T& packed,
|
||||||
if ((table_tag == HB_OT_TAG_GPOS
|
if ((table_tag == HB_OT_TAG_GPOS
|
||||||
|| table_tag == HB_OT_TAG_GSUB)
|
|| table_tag == HB_OT_TAG_GSUB)
|
||||||
&& will_overflow)
|
&& will_overflow)
|
||||||
|
{
|
||||||
|
if (recalculate_extensions)
|
||||||
{
|
{
|
||||||
graph::make_extension_context_t ext_context (table_tag, sorted_graph, extension_buffer);
|
graph::make_extension_context_t ext_context (table_tag, sorted_graph, extension_buffer);
|
||||||
if (ext_context.in_error ())
|
if (ext_context.in_error ())
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
if (0 && !_promote_extensions_if_needed (ext_context)) {
|
if (!_promote_extensions_if_needed (ext_context)) {
|
||||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
|
DEBUG_MSG (SUBSET_REPACK, nullptr, "Extensions promotion failed.");
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
|
DEBUG_MSG (SUBSET_REPACK, nullptr, "Assigning spaces to 32 bit subgraphs.");
|
||||||
if (sorted_graph.assign_spaces ())
|
if (sorted_graph.assign_spaces ())
|
||||||
|
|
Loading…
Reference in New Issue