xref: /aosp_15_r20/external/harfbuzz_ng/perf/benchmark-font.cc (revision 2d1272b857b1f7575e6e246373e1cb218663db8a)
1 #include "hb-benchmark.hh"
2 
3 #define SUBSET_FONT_BASE_PATH "test/subset/data/fonts/"
4 
5 struct test_input_t
6 {
7   bool is_variable;
8   const char *font_path;
9 } default_tests[] =
10 {
11   {false, SUBSET_FONT_BASE_PATH "Roboto-Regular.ttf"},
12   {true , SUBSET_FONT_BASE_PATH "RobotoFlex-Variable.ttf"},
13   {false, SUBSET_FONT_BASE_PATH "SourceSansPro-Regular.otf"},
14   {true , SUBSET_FONT_BASE_PATH "AdobeVFPrototype.otf"},
15   {true , SUBSET_FONT_BASE_PATH "SourceSerifVariable-Roman.ttf"},
16   {false, SUBSET_FONT_BASE_PATH "Comfortaa-Regular-new.ttf"},
17   {false, SUBSET_FONT_BASE_PATH "NotoNastaliqUrdu-Regular.ttf"},
18   {false, SUBSET_FONT_BASE_PATH "NotoSerifMyanmar-Regular.otf"},
19 };
20 
21 static test_input_t *tests = default_tests;
22 static unsigned num_tests = sizeof (default_tests) / sizeof (default_tests[0]);
23 
24 enum backend_t { HARFBUZZ, FREETYPE, CORETEXT };
25 
26 enum operation_t
27 {
28   nominal_glyphs,
29   glyph_h_advances,
30   glyph_extents,
31   draw_glyph,
32   paint_glyph,
33   load_face_and_shape,
34 };
35 
36 static void
_hb_move_to(hb_draw_funcs_t *,void * draw_data,hb_draw_state_t *,float x,float y,void *)37 _hb_move_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *)
38 {
39   float &i = * (float *) draw_data;
40   i += x + y;
41 }
42 
43 static void
_hb_line_to(hb_draw_funcs_t *,void * draw_data,hb_draw_state_t *,float x,float y,void *)44 _hb_line_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float x, float y, void *)
45 {
46   float &i = * (float *) draw_data;
47   i += x + y;
48 }
49 
50 static void
_hb_quadratic_to(hb_draw_funcs_t *,void * draw_data,hb_draw_state_t *,float cx,float cy,float x,float y,void *)51 _hb_quadratic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx, float cy, float x, float y, void *)
52 {
53   float &i = * (float *) draw_data;
54   i += cx + cy + x + y;
55 }
56 
57 static void
_hb_cubic_to(hb_draw_funcs_t *,void * draw_data,hb_draw_state_t *,float cx1,float cy1,float cx2,float cy2,float x,float y,void *)58 _hb_cubic_to (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, float cx1, float cy1, float cx2, float cy2, float x, float y, void *)
59 {
60   float &i = * (float *) draw_data;
61   i += cx1 + cy1 + cx2 + cy2 + x + y;
62 }
63 
64 static void
_hb_close_path(hb_draw_funcs_t *,void * draw_data,hb_draw_state_t *,void *)65 _hb_close_path (hb_draw_funcs_t *, void *draw_data, hb_draw_state_t *, void *)
66 {
67   float &i = * (float *) draw_data;
68   i += 1.0;
69 }
70 
71 static hb_draw_funcs_t *
_draw_funcs_create(void)72 _draw_funcs_create (void)
73 {
74   hb_draw_funcs_t *draw_funcs = hb_draw_funcs_create ();
75   hb_draw_funcs_set_move_to_func (draw_funcs, _hb_move_to, nullptr, nullptr);
76   hb_draw_funcs_set_line_to_func (draw_funcs, _hb_line_to, nullptr, nullptr);
77   hb_draw_funcs_set_quadratic_to_func (draw_funcs, _hb_quadratic_to, nullptr, nullptr);
78   hb_draw_funcs_set_cubic_to_func (draw_funcs, _hb_cubic_to, nullptr, nullptr);
79   hb_draw_funcs_set_close_path_func (draw_funcs, _hb_close_path, nullptr, nullptr);
80   return draw_funcs;
81 }
82 
BM_Font(benchmark::State & state,bool is_var,backend_t backend,operation_t operation,const test_input_t & test_input)83 static void BM_Font (benchmark::State &state,
84 		     bool is_var, backend_t backend, operation_t operation,
85 		     const test_input_t &test_input)
86 {
87   hb_font_t *font;
88   unsigned num_glyphs;
89   {
90     hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
91     assert (face);
92     num_glyphs = hb_face_get_glyph_count (face);
93     font = hb_font_create (face);
94     hb_face_destroy (face);
95   }
96 
97   if (is_var)
98   {
99     hb_variation_t wght = {HB_TAG ('w','g','h','t'), 500};
100     hb_font_set_variations (font, &wght, 1);
101   }
102 
103   switch (backend)
104   {
105     case HARFBUZZ:
106       hb_ot_font_set_funcs (font);
107       break;
108 
109     case FREETYPE:
110 #ifdef HAVE_FREETYPE
111       hb_ft_font_set_funcs (font);
112 #endif
113       break;
114 
115     case CORETEXT:
116 #ifdef HAVE_CORETEXT
117       hb_coretext_font_set_funcs (font);
118 #endif
119       break;
120   }
121 
122   switch (operation)
123   {
124     case nominal_glyphs:
125     {
126       hb_set_t *set = hb_set_create ();
127       hb_face_collect_unicodes (hb_font_get_face (font), set);
128       unsigned pop = hb_set_get_population (set);
129       hb_codepoint_t *unicodes = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
130       hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (pop, sizeof (hb_codepoint_t));
131 
132       hb_codepoint_t *p = unicodes;
133       for (hb_codepoint_t u = HB_SET_VALUE_INVALID;
134 	   hb_set_next (set, &u);)
135         *p++ = u;
136       assert (p == unicodes + pop);
137 
138       for (auto _ : state)
139 	hb_font_get_nominal_glyphs (font,
140 				    pop,
141 				    unicodes, sizeof (*unicodes),
142 				    glyphs, sizeof (*glyphs));
143 
144       free (glyphs);
145       free (unicodes);
146       hb_set_destroy (set);
147       break;
148     }
149     case glyph_h_advances:
150     {
151       hb_codepoint_t *glyphs = (hb_codepoint_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
152       hb_position_t *advances = (hb_position_t *) calloc (num_glyphs, sizeof (hb_codepoint_t));
153 
154       for (unsigned g = 0; g < num_glyphs; g++)
155         glyphs[g] = g;
156 
157       for (auto _ : state)
158 	hb_font_get_glyph_h_advances (font,
159 				      num_glyphs,
160 				      glyphs, sizeof (*glyphs),
161 				      advances, sizeof (*advances));
162 
163       free (advances);
164       free (glyphs);
165       break;
166     }
167     case glyph_extents:
168     {
169       hb_glyph_extents_t extents;
170       for (auto _ : state)
171 	for (unsigned gid = 0; gid < num_glyphs; ++gid)
172 	  hb_font_get_glyph_extents (font, gid, &extents);
173       break;
174     }
175     case draw_glyph:
176     {
177       hb_draw_funcs_t *draw_funcs = _draw_funcs_create ();
178       for (auto _ : state)
179       {
180 	float i = 0;
181 	for (unsigned gid = 0; gid < num_glyphs; ++gid)
182 	  hb_font_draw_glyph (font, gid, draw_funcs, &i);
183       }
184       hb_draw_funcs_destroy (draw_funcs);
185       break;
186     }
187     case paint_glyph:
188     {
189       hb_paint_funcs_t *paint_funcs = hb_paint_funcs_create ();
190       for (auto _ : state)
191       {
192 	for (unsigned gid = 0; gid < num_glyphs; ++gid)
193 	  hb_font_paint_glyph (font, gid, paint_funcs, nullptr, 0, 0);
194       }
195       hb_paint_funcs_destroy (paint_funcs);
196       break;
197     }
198     case load_face_and_shape:
199     {
200       for (auto _ : state)
201       {
202 	hb_face_t *face = hb_benchmark_face_create_from_file_or_fail (test_input.font_path, 0);
203 	assert (face);
204 	hb_font_t *font = hb_font_create (face);
205 	hb_face_destroy (face);
206 
207 	switch (backend)
208 	{
209 	  case HARFBUZZ:
210 	    hb_ot_font_set_funcs (font);
211 	    break;
212 
213 	  case FREETYPE:
214 #ifdef HAVE_FREETYPE
215 	    hb_ft_font_set_funcs (font);
216 #endif
217 	    break;
218 
219 	  case CORETEXT:
220 #ifdef HAVE_CORETEXT
221 	    hb_coretext_font_set_funcs (font);
222 #endif
223 	    break;
224 	}
225 
226 	hb_buffer_t *buffer = hb_buffer_create ();
227 	hb_buffer_add_utf8 (buffer, " ", -1, 0, -1);
228 	hb_buffer_guess_segment_properties (buffer);
229 
230 	hb_shape (font, buffer, nullptr, 0);
231 
232 	hb_buffer_destroy (buffer);
233 	hb_font_destroy (font);
234       }
235       break;
236     }
237   }
238 
239 
240   hb_font_destroy (font);
241 }
242 
test_backend(backend_t backend,const char * backend_name,bool variable,operation_t op,const char * op_name,benchmark::TimeUnit time_unit,const test_input_t & test_input)243 static void test_backend (backend_t backend,
244 			  const char *backend_name,
245 			  bool variable,
246 			  operation_t op,
247 			  const char *op_name,
248 			  benchmark::TimeUnit time_unit,
249 			  const test_input_t &test_input)
250 {
251   char name[1024] = "BM_Font/";
252   strcat (name, op_name);
253   strcat (name, "/");
254   const char *p = strrchr (test_input.font_path, '/');
255   strcat (name, p ? p + 1 : test_input.font_path);
256   strcat (name, variable ? "/var" : "");
257   strcat (name, "/");
258   strcat (name, backend_name);
259 
260   benchmark::RegisterBenchmark (name, BM_Font, variable, backend, op, test_input)
261    ->Unit(time_unit);
262 }
263 
test_operation(operation_t op,const char * op_name,benchmark::TimeUnit time_unit)264 static void test_operation (operation_t op,
265 			    const char *op_name,
266 			    benchmark::TimeUnit time_unit)
267 {
268   for (unsigned i = 0; i < num_tests; i++)
269   {
270     auto& test_input = tests[i];
271     for (int variable = 0; variable < int (test_input.is_variable) + 1; variable++)
272     {
273       bool is_var = (bool) variable;
274 
275       test_backend (HARFBUZZ, "hb", is_var, op, op_name, time_unit, test_input);
276 #ifdef HAVE_FREETYPE
277       test_backend (FREETYPE, "ft", is_var, op, op_name, time_unit, test_input);
278 #endif
279 #ifdef HAVE_CORETEXT
280       test_backend (CORETEXT, "coretext", is_var, op, op_name, time_unit, test_input);
281 #endif
282     }
283   }
284 }
285 
main(int argc,char ** argv)286 int main(int argc, char** argv)
287 {
288   benchmark::Initialize(&argc, argv);
289 
290   if (argc > 1)
291   {
292     num_tests = argc - 1;
293     tests = (test_input_t *) calloc (num_tests, sizeof (test_input_t));
294     for (unsigned i = 0; i < num_tests; i++)
295     {
296       tests[i].is_variable = true;
297       tests[i].font_path = argv[i + 1];
298     }
299   }
300 
301 #define TEST_OPERATION(op, time_unit) test_operation (op, #op, time_unit)
302 
303   TEST_OPERATION (nominal_glyphs, benchmark::kMicrosecond);
304   TEST_OPERATION (glyph_h_advances, benchmark::kMicrosecond);
305   TEST_OPERATION (glyph_extents, benchmark::kMicrosecond);
306   TEST_OPERATION (draw_glyph, benchmark::kMicrosecond);
307   TEST_OPERATION (paint_glyph, benchmark::kMillisecond);
308   TEST_OPERATION (load_face_and_shape, benchmark::kMicrosecond);
309 
310 #undef TEST_OPERATION
311 
312   benchmark::RunSpecifiedBenchmarks();
313   benchmark::Shutdown();
314 
315   if (tests != default_tests)
316     free (tests);
317 }
318