[repacker] handle a couple of duplication edge cases.

- Detect cases where there are multiple links from a parent to a child. Don't duplicate that child if those are the only remaining links to the child.
- Correctly handle isolating a subgraph where the root idx has multiple incoming links.
This commit is contained in:
Garret Rieger 2021-09-10 14:55:24 -07:00
parent c19ec97da7
commit fe155de989
1 changed files with 36 additions and 11 deletions

View File

@ -366,10 +366,15 @@ struct graph_t
*/ */
bool isolate_subgraph (unsigned root_idx) bool isolate_subgraph (unsigned root_idx)
{ {
update_incoming_edge_count ();
hb_hashmap_t<unsigned, unsigned> subgraph; hb_hashmap_t<unsigned, unsigned> subgraph;
hb_hashmap_t<unsigned, unsigned> index_map;
// incoming edges to root_idx should be all 32 bit in length so we don't need to de-dup these
// set the subgraph incoming edge count to match all of root_idx's incoming edges
subgraph.set (root_idx, vertices_[root_idx].incoming_edges);
find_subgraph(root_idx, subgraph); find_subgraph(root_idx, subgraph);
hb_hashmap_t<unsigned, unsigned> index_map;
bool made_changes = false; bool made_changes = false;
for (auto entry : subgraph.iter ()) for (auto entry : subgraph.iter ())
{ {
@ -393,15 +398,16 @@ struct graph_t
void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph) void find_subgraph (unsigned node_idx, hb_hashmap_t<unsigned, unsigned>& subgraph)
{ {
if (subgraph.has (node_idx))
{
subgraph.set (node_idx, subgraph[node_idx] + 1);
return;
}
subgraph.set (node_idx, 1);
for (const auto& link : vertices_[node_idx].obj.links) for (const auto& link : vertices_[node_idx].obj.links)
{
if (subgraph.has (link.objidx))
{
subgraph.set (link.objidx, subgraph[link.objidx] + 1);
continue;
}
subgraph.set (link.objidx, 1);
find_subgraph (link.objidx, subgraph); find_subgraph (link.objidx, subgraph);
}
} }
/* /*
@ -466,13 +472,30 @@ struct graph_t
* parent to the clone. The copy is a shallow copy, objects * parent to the clone. The copy is a shallow copy, objects
* linked from child are not duplicated. * linked from child are not duplicated.
*/ */
void duplicate (unsigned parent_idx, unsigned child_idx) bool duplicate (unsigned parent_idx, unsigned child_idx)
{ {
update_incoming_edge_count ();
unsigned links_to_child = 0;
for (const auto& l : vertices_[parent_idx].obj.links)
{
if (l.objidx == child_idx) links_to_child++;
}
if (vertices_[child_idx].incoming_edges <= links_to_child)
{
// Can't duplicate this node, doing so would orphan the original one as all remaining links
// to child are from parent.
DEBUG_MSG (SUBSET_REPACK, nullptr, " Not duplicating %d => %d",
parent_idx, child_idx);
return false;
}
DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d", DEBUG_MSG (SUBSET_REPACK, nullptr, " Duplicating %d => %d",
parent_idx, child_idx); parent_idx, child_idx);
unsigned clone_idx = duplicate (child_idx); unsigned clone_idx = duplicate (child_idx);
if (clone_idx == (unsigned) -1) return; if (clone_idx == (unsigned) -1) return false;
// duplicate shifts the root node idx, so if parent_idx was root update it. // duplicate shifts the root node idx, so if parent_idx was root update it.
if (parent_idx == clone_idx) parent_idx++; if (parent_idx == clone_idx) parent_idx++;
auto& clone = vertices_[clone_idx]; auto& clone = vertices_[clone_idx];
@ -489,6 +512,8 @@ struct graph_t
child.incoming_edges--; child.incoming_edges--;
} }
} }
return true;
} }
/* /*
@ -819,7 +844,7 @@ static bool _process_overflows (const hb_vector_t<graph_t::overflow_record_t>& o
{ {
// The child object is shared, we may be able to eliminate the overflow // The child object is shared, we may be able to eliminate the overflow
// by duplicating it. // by duplicating it.
sorted_graph.duplicate (r.parent, r.child); if (!sorted_graph.duplicate (r.parent, r.child)) continue;
return true; return true;
} }