mirror of
https://gitlab.gnome.org/GNOME/gtk.git
synced 2024-11-08 17:50:10 +00:00
diff: Allow aborting a diff
When the max cost for finding a path gets to high, the diff can now be aborted. Because render nodes have a fallback method (by just marking the whole bounds of the nodes as different), we use this to improve performance of diffs. This brings fishbowl (which is basically a container node with N images that change every frame) back to close to previous performance.
This commit is contained in:
parent
144637bff1
commit
200bbe8fda
@ -36,6 +36,8 @@ struct _GskDiffSettings {
|
||||
GskKeepFunc keep_func;
|
||||
GskDeleteFunc delete_func;
|
||||
GskInsertFunc insert_func;
|
||||
|
||||
guint allow_abort : 1;
|
||||
};
|
||||
|
||||
typedef struct _SplitResult {
|
||||
@ -61,6 +63,13 @@ gsk_diff_settings_new (GCompareDataFunc compare_func,
|
||||
return settings;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_diff_settings_set_allow_abort (GskDiffSettings *settings,
|
||||
gboolean allow_abort)
|
||||
{
|
||||
settings->allow_abort = allow_abort;
|
||||
}
|
||||
|
||||
void
|
||||
gsk_diff_settings_free (GskDiffSettings *settings)
|
||||
{
|
||||
@ -76,7 +85,7 @@ gsk_diff_settings_free (GskDiffSettings *settings)
|
||||
* cases using this algorithm is full, so a little bit of heuristic is needed
|
||||
* to cut the search and to return a suboptimal point.
|
||||
*/
|
||||
static void
|
||||
static GskDiffResult
|
||||
split (gconstpointer *elem1,
|
||||
gssize off1,
|
||||
gssize lim1,
|
||||
@ -144,7 +153,7 @@ split (gconstpointer *elem1,
|
||||
spl->i1 = i1;
|
||||
spl->i2 = i2;
|
||||
spl->min_lo = spl->min_hi = 1;
|
||||
return;
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -185,7 +194,7 @@ split (gconstpointer *elem1,
|
||||
spl->i1 = i1;
|
||||
spl->i2 = i2;
|
||||
spl->min_lo = spl->min_hi = 1;
|
||||
return;
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -195,7 +204,7 @@ split (gconstpointer *elem1,
|
||||
/*
|
||||
* If the edit cost is above the heuristic trigger and if
|
||||
* we got a good snake, we sample current diagonals to see
|
||||
* if some of the, have reached an "interesting" path. Our
|
||||
* if some of them have reached an "interesting" path. Our
|
||||
* measure is a function of the distance from the diagonal
|
||||
* corner (i1 + i2) penalized with the distance from the
|
||||
* mid diagonal itself. If this value is above the current
|
||||
@ -233,7 +242,7 @@ split (gconstpointer *elem1,
|
||||
{
|
||||
spl->min_lo = 1;
|
||||
spl->min_hi = 0;
|
||||
return;
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
|
||||
for (best = 0, d = bmax; d >= bmin; d -= 2)
|
||||
@ -266,7 +275,7 @@ split (gconstpointer *elem1,
|
||||
{
|
||||
spl->min_lo = 0;
|
||||
spl->min_hi = 1;
|
||||
return;
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
}
|
||||
|
||||
@ -278,6 +287,9 @@ split (gconstpointer *elem1,
|
||||
{
|
||||
gssize fbest, fbest1, bbest, bbest1;
|
||||
|
||||
if (settings->allow_abort)
|
||||
return GSK_DIFF_ABORTED;
|
||||
|
||||
fbest = fbest1 = -1;
|
||||
for (d = fmax; d >= fmin; d -= 2)
|
||||
{
|
||||
@ -321,7 +333,7 @@ split (gconstpointer *elem1,
|
||||
spl->min_hi = 1;
|
||||
}
|
||||
|
||||
return;
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -331,7 +343,7 @@ split (gconstpointer *elem1,
|
||||
* the box splitting function. Note that the real job (marking changed lines)
|
||||
* is done in the two boundary reaching checks.
|
||||
*/
|
||||
static void
|
||||
static GskDiffResult
|
||||
compare (gconstpointer *elem1,
|
||||
gssize off1,
|
||||
gssize lim1,
|
||||
@ -384,27 +396,37 @@ compare (gconstpointer *elem1,
|
||||
else
|
||||
{
|
||||
SplitResult spl = { 0, };
|
||||
GskDiffResult res;
|
||||
|
||||
/*
|
||||
* Divide ...
|
||||
*/
|
||||
split (elem1, off1, lim1,
|
||||
elem2, off2, lim2,
|
||||
kvdf, kvdb, need_min,
|
||||
settings, data,
|
||||
&spl);
|
||||
res = split (elem1, off1, lim1,
|
||||
elem2, off2, lim2,
|
||||
kvdf, kvdb, need_min,
|
||||
settings, data,
|
||||
&spl);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
|
||||
/*
|
||||
* ... et Impera.
|
||||
*/
|
||||
compare (elem1, off1, spl.i1,
|
||||
elem2, off2, spl.i2,
|
||||
kvdf, kvdb, spl.min_lo,
|
||||
settings, data);
|
||||
compare (elem1, spl.i1, lim1,
|
||||
elem2, spl.i2, lim2,
|
||||
kvdf, kvdb, spl.min_hi,
|
||||
settings, data);
|
||||
res = compare (elem1, off1, spl.i1,
|
||||
elem2, off2, spl.i2,
|
||||
kvdf, kvdb, spl.min_lo,
|
||||
settings, data);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
res = compare (elem1, spl.i1, lim1,
|
||||
elem2, spl.i2, lim2,
|
||||
kvdf, kvdb, spl.min_hi,
|
||||
settings, data);
|
||||
if (res != GSK_DIFF_OK)
|
||||
return res;
|
||||
}
|
||||
|
||||
return GSK_DIFF_OK;
|
||||
}
|
||||
|
||||
#if 0
|
||||
@ -435,7 +457,7 @@ compare (gconstpointer *elem1,
|
||||
dd2.rindex = xe->xdf2.rindex;
|
||||
#endif
|
||||
|
||||
void
|
||||
GskDiffResult
|
||||
gsk_diff (gconstpointer *elem1,
|
||||
gsize n1,
|
||||
gconstpointer *elem2,
|
||||
@ -445,6 +467,7 @@ gsk_diff (gconstpointer *elem1,
|
||||
{
|
||||
gsize ndiags;
|
||||
gssize *kvd, *kvdf, *kvdb;
|
||||
GskDiffResult res;
|
||||
|
||||
ndiags = n1 + n2 + 3;
|
||||
|
||||
@ -454,11 +477,13 @@ gsk_diff (gconstpointer *elem1,
|
||||
kvdf += n2 + 1;
|
||||
kvdb += n2 + 1;
|
||||
|
||||
compare (elem1, 0, n1,
|
||||
elem2, 0, n2,
|
||||
kvdf, kvdb, FALSE,
|
||||
settings, data);
|
||||
res = compare (elem1, 0, n1,
|
||||
elem2, 0, n2,
|
||||
kvdf, kvdb, FALSE,
|
||||
settings, data);
|
||||
|
||||
g_free (kvd);
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
|
@ -24,6 +24,11 @@
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
GSK_DIFF_OK = 0,
|
||||
GSK_DIFF_ABORTED,
|
||||
} GskDiffResult;
|
||||
|
||||
typedef void (* GskKeepFunc) (gconstpointer elem1, gconstpointer elem2, gpointer data);
|
||||
typedef void (* GskDeleteFunc) (gconstpointer elem, gsize idx, gpointer data);
|
||||
typedef void (* GskInsertFunc) (gconstpointer elem, gsize idx, gpointer data);
|
||||
@ -35,8 +40,10 @@ GskDiffSettings * gsk_diff_settings_new (GCompareDataFun
|
||||
GskDeleteFunc delete_func,
|
||||
GskInsertFunc insert_func);
|
||||
void gsk_diff_settings_free (GskDiffSettings *settings);
|
||||
void gsk_diff_settings_set_allow_abort (GskDiffSettings *settings,
|
||||
gboolean allow_abort);
|
||||
|
||||
void gsk_diff (gconstpointer *elem1,
|
||||
GskDiffResult gsk_diff (gconstpointer *elem1,
|
||||
gsize n1,
|
||||
gconstpointer *elem2,
|
||||
gsize n2,
|
||||
|
@ -2193,6 +2193,7 @@ gsk_container_node_get_diff_settings (void)
|
||||
gsk_container_node_keep_func,
|
||||
gsk_container_node_change_func,
|
||||
gsk_container_node_change_func);
|
||||
gsk_diff_settings_set_allow_abort (settings, TRUE);
|
||||
|
||||
return settings;
|
||||
}
|
||||
@ -2205,12 +2206,15 @@ gsk_container_node_diff (GskRenderNode *node1,
|
||||
GskContainerNode *self1 = (GskContainerNode *) node1;
|
||||
GskContainerNode *self2 = (GskContainerNode *) node2;
|
||||
|
||||
gsk_diff ((gconstpointer *) self1->children,
|
||||
self1->n_children,
|
||||
(gconstpointer *) self2->children,
|
||||
self2->n_children,
|
||||
gsk_container_node_get_diff_settings (),
|
||||
region);
|
||||
if (gsk_diff ((gconstpointer *) self1->children,
|
||||
self1->n_children,
|
||||
(gconstpointer *) self2->children,
|
||||
self2->n_children,
|
||||
gsk_container_node_get_diff_settings (),
|
||||
region) == GSK_DIFF_OK)
|
||||
return;
|
||||
|
||||
gsk_render_node_diff_impossible (node1, node2, region);
|
||||
}
|
||||
|
||||
static void
|
||||
|
Loading…
Reference in New Issue
Block a user