aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPo Lu2023-12-25 11:21:15 +0800
committerPo Lu2023-12-25 11:21:15 +0800
commit995dd36da1df70c55ef2e72d4ff5b2641cc83292 (patch)
treef00cd748784e04cb919c9f74e32c540ec0542dca
parent62f2c4386259f998442e8098d8a368835a36fb65 (diff)
downloademacs-995dd36da1df70c55ef2e72d4ff5b2641cc83292.tar.gz
emacs-995dd36da1df70c55ef2e72d4ff5b2641cc83292.zip
Optimize font edge filling loop
* src/sfnt.c (sfnt_fedge_sort): Delete function. (sfnt_poly_edges_exact): Don't sort edges, iterate through each instead. (main): Adjust tests.
-rw-r--r--src/sfnt.c87
1 files changed, 33 insertions, 54 deletions
diff --git a/src/sfnt.c b/src/sfnt.c
index 553b828a2db..d945342c264 100644
--- a/src/sfnt.c
+++ b/src/sfnt.c
@@ -4946,36 +4946,6 @@ sfnt_insert_raster_step (struct sfnt_step_raster *raster,
4946 step->coverage += coverage; 4946 step->coverage += coverage;
4947} 4947}
4948 4948
4949/* Sort an array of SIZE edges to increase by bottom Y position, in
4950 preparation for building spans.
4951
4952 Insertion sort is used because there are usually not very many
4953 edges, and anything larger would bloat up the code. */
4954
4955static void
4956sfnt_fedge_sort (struct sfnt_fedge *edges, size_t size)
4957{
4958 ssize_t i, j;
4959 struct sfnt_fedge edge;
4960
4961 for (i = 1; i < size; ++i)
4962 {
4963 edge = edges[i];
4964 j = i - 1;
4965
4966 /* Comparing truncated values yields a faint speedup, for not as
4967 many edges must be moved as would be otherwise. */
4968 while (j >= 0 && ((int) edges[j].bottom
4969 > (int) edge.bottom))
4970 {
4971 edges[j + 1] = edges[j];
4972 j--;
4973 }
4974
4975 edges[j + 1] = edge;
4976 }
4977}
4978
4979/* Draw EDGES, an unsorted array of polygon edges of size NEDGES. 4949/* Draw EDGES, an unsorted array of polygon edges of size NEDGES.
4980 4950
4981 Transform EDGES into an array of steps representing a raster with 4951 Transform EDGES into an array of steps representing a raster with
@@ -4993,23 +4963,19 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges,
4993 sfnt_step_raster_proc proc, void *dcontext) 4963 sfnt_step_raster_proc proc, void *dcontext)
4994{ 4964{
4995 int y; 4965 int y;
4996 size_t size, e; 4966 size_t size, e, edges_processed;
4997 struct sfnt_fedge *active, **prev, *a; 4967 struct sfnt_fedge *active, **prev, *a, sentinel;
4998 struct sfnt_step_raster raster; 4968 struct sfnt_step_raster raster;
4999 struct sfnt_step_chunk *next, *last; 4969 struct sfnt_step_chunk *next, *last;
5000 4970
5001 if (!height) 4971 if (!height)
5002 return; 4972 return;
5003 4973
5004 /* Sort edges to ascend by Y-order. Once again, remember: cartesian
5005 coordinates. */
5006 sfnt_fedge_sort (edges, nedges);
5007
5008 /* Step down line by line. Find active edges. */ 4974 /* Step down line by line. Find active edges. */
5009 4975
5010 y = sfnt_floor_fixed (MAX (0, edges[0].bottom)); 4976 y = sfnt_floor_fixed (MAX (0, edges[0].bottom));
5011 e = 0; 4977 e = edges_processed = 0;
5012 active = NULL; 4978 active = &sentinel;
5013 4979
5014 /* Allocate the array of edges. */ 4980 /* Allocate the array of edges. */
5015 4981
@@ -5023,20 +4989,28 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges,
5023 4989
5024 for (; y != height; y += 1) 4990 for (; y != height; y += 1)
5025 { 4991 {
5026 /* Add in new edges keeping them sorted. */ 4992 /* Run over the whole array on each iteration of this loop;
5027 for (; e < nedges && edges[e].bottom < y + 1; ++e) 4993 experiments demonstrate this is faster for the majority of
4994 glyphs. */
4995 for (e = 0; e < nedges; ++e)
5028 { 4996 {
5029 if (edges[e].top > y) 4997 /* Although edges is unsorted, edges which have already been
4998 processed will see their next fields set, and can thus be
4999 disregarded. */
5000 if (!edges[e].next
5001 && (edges[e].bottom < y + 1)
5002 && (edges[e].top > y))
5030 { 5003 {
5031 /* Find where to place this edge. */ 5004 /* As steps generated from each edge are sorted at the
5032 for (prev = &active; (a = *prev); prev = &(a->next)) 5005 time of their insertion, sorting the list of active
5033 { 5006 edges itself is redundant. */
5034 if (a->x > edges[e].x) 5007 edges[e].next = active;
5035 break; 5008 active = &edges[e];
5036 } 5009
5037 5010 /* Increment the counter recording the number of edges
5038 edges[e].next = *prev; 5011 processed, which is used to terminate this loop early
5039 *prev = &edges[e]; 5012 once all have been processed. */
5013 edges_processed++;
5040 } 5014 }
5041 } 5015 }
5042 5016
@@ -5044,7 +5018,7 @@ sfnt_poly_edges_exact (struct sfnt_fedge *edges, size_t nedges,
5044 removing it if it does not overlap with the next 5018 removing it if it does not overlap with the next
5045 scanline. */ 5019 scanline. */
5046 5020
5047 for (prev = &active; (a = *prev);) 5021 for (prev = &active; (a = *prev) != &sentinel;)
5048 { 5022 {
5049 float x_top, x_bot, x_min, x_max; 5023 float x_top, x_bot, x_min, x_max;
5050 float y_top, y_bot; 5024 float y_top, y_bot;
@@ -5371,11 +5345,15 @@ be as well. */
5371 if (a->top < y + 1) 5345 if (a->top < y + 1)
5372 *prev = a->next; 5346 *prev = a->next;
5373 else 5347 else
5348 /* This edge doesn't intersect with the next scanline;
5349 remove it from the list. After the edge at hand is so
5350 deleted from the list, its next field remains set,
5351 excluding it from future consideration. */
5374 prev = &a->next; 5352 prev = &a->next;
5375 } 5353 }
5376 5354
5377 /* Break if all is done. */ 5355 /* Break if all is done. */
5378 if (!active && e == nedges) 5356 if (active == &sentinel && edges_processed == nedges)
5379 break; 5357 break;
5380 } 5358 }
5381 5359
@@ -21139,7 +21117,7 @@ main (int argc, char **argv)
21139 21117
21140 clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start); 21118 clock_gettime (CLOCK_THREAD_CPUTIME_ID, &start);
21141 21119
21142 for (i = 0; i < 800; ++i) 21120 for (i = 0; i < 12800; ++i)
21143 { 21121 {
21144 xfree (raster); 21122 xfree (raster);
21145 raster = (*test_raster_glyph_outline) (outline); 21123 raster = (*test_raster_glyph_outline) (outline);
@@ -21265,7 +21243,8 @@ main (int argc, char **argv)
21265 printf ("time spent building edges: %lld sec %ld nsec\n", 21243 printf ("time spent building edges: %lld sec %ld nsec\n",
21266 (long long) sub1.tv_sec, sub1.tv_nsec); 21244 (long long) sub1.tv_sec, sub1.tv_nsec);
21267 printf ("time spent rasterizing: %lld sec %ld nsec\n", 21245 printf ("time spent rasterizing: %lld sec %ld nsec\n",
21268 (long long) sub2.tv_sec / 800, sub2.tv_nsec / 800); 21246 (long long) sub2.tv_sec / 12800,
21247 sub2.tv_nsec / 12800);
21269 21248
21270 xfree (outline); 21249 xfree (outline);
21271 } 21250 }