Re: hb-raster: a new CPU rasterizer

Behdad Esfahbod <[email protected]> Thu, 26 Feb 2026 14:47:10 -0300
Newsgroups gmane.comp.freedesktop.harfbuzz,gmane.comp.fonts.freetype.devel
Message-ID <CAF63+7UN+swkWcj1JCwjr6hRTrkbGLGAeCy_uyHYKb64grigUQ@mail.gmail.com>
--00000000000050c08e064bbdb73c
Content-Type: text/plain; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

Hi Alexei,

I don't have a Linux machine handy to get good perf numbers until mid
March. But looking at the FT code vs mine, a few things pop out:

- gray_render_line seems to be doing a lot of int divisions. My code avoids
divisions by converting them to multiplies by keeping slope instead.

- gray_render_line does the integration as it goes? I do a final pass for
integration that is fused to the pixel fill. The pixel fill is done in
SIMD, which gave me a nice boost.

Here's a few more numbers: With NotoSerifCJK-Varsc:

At 400ppem, FreeType is ~10s, font.rs is ~10s, hb-raster is ~5s.
At 40ppem, FreeType is 4.2s, font.rs is 3.6s, hb-raster is 3.1s.
At 12ppem, FreeType is 2.3s, font.rs is 1.78s, hb-raster is 1.92s.

I'll get more numbers when I'm home.

Thanks,

behdad
http://behdad.org/


On Wed, Feb 25, 2026 at 9:24=E2=80=AFAM Alexei Podtelezhnikov <apodtele@gma=
il.com>
wrote:

> Behdad,
>
> > With help from my AI assistants, I finally put together a rasterizer in
> HarfBuzz, in a new harfbuzz-raster library. Accompanying the rasterizer i=
s
> a COLRv1 color-font renderer, but I like to focus on the rasterizer in th=
is
> email:
>
> Congratulations!
>
> > While it was designed from scratch, the general algorithm is similar to
> FreeType's, that is, a coverage based AA rasterizer. From there though,
> different approaches are taken. The end result is that the code runs 2x o=
r
> more faster than FreeType's in my testing.
>
> Do you mind dissecting the performance of your rasterizer a bit
> further with the perf counter? This would help to compare performance
> more carefully. For example,
> $ perf record bin/ftbench -f2 -s32 -bc tahoma.ttf
> $ perf report
>
>   26.49%  ftbench  libfreetype.so.6.20.4  [.] gray_render_line
>   19.30%  ftbench  libfreetype.so.6.20.4  [.] gray_set_cell
>   18.37%  ftbench  libfreetype.so.6.20.4  [.] gray_convert_glyph
>    7.78%  ftbench  libfreetype.so.6.20.4  [.] TT_Load_Simple_Glyph
>    4.92%  ftbench  libfreetype.so.6.20.4  [.] gray_conic_to
>
> This shows how FreeType rasterizer spends its time at 32 ppem. After
> subtracting other activities, the curve and line integration is about
> 40%, the pixel list management is 30%, the final sweep is 30%. I
> suspect that the linked list management is what you avoid at the
> expense of more memory usage, with a faster sweep too.
>
> > I long had intuited that a tightly woven rasterizer code will perform
> really well, and this experiment seems to prove that. The code is very
> short (~1000 lines) and readable:
> >
> >   https://github.com/harfbuzz/harfbuzz/blob/main/src/hb-raster-draw.cc
>
> Thanks,
> Alexei
>

--00000000000050c08e064bbdb73c
Content-Type: text/html; charset="UTF-8"
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr"><div>Hi Alexei,</div><div><br></div><div>I don&#39;t have =
a Linux machine handy to get good perf numbers until mid March. But looking=
 at the FT code vs mine, a few things pop out:</div><div><br></div><div>- g=
ray_render_line seems to be doing a lot of int divisions. My code avoids di=
visions by converting them to multiplies by keeping slope instead.</div><di=
v><br></div><div>- gray_render_line does the integration=C2=A0as it goes? I=
 do a final pass for integration that is fused to the pixel fill. The pixel=
 fill is done in SIMD, which gave me a nice boost.</div><div><br></div><div=
>Here&#39;s a few more numbers: With NotoSerifCJK-Varsc:</div><div><br></di=
v><div>At 400ppem, FreeType is ~10s, font.rs is ~10s, hb-raster is ~5s.</di=
v><div>At 40ppem, FreeType is 4.2s, font.rs is 3.6s, hb-raster is 3.1s.<br>=
At 12ppem, FreeType is 2.3s, font.rs is 1.78s, hb-raster is 1.92s.</div><di=
v><br></div><div>I&#39;ll get more numbers when I&#39;m home.</div><div><br=
></div><div>Thanks,</div><div><br></div><div><div dir=3D"ltr" class=3D"gmai=
l_signature" data-smartmail=3D"gmail_signature">behdad<br><a href=3D"http:/=
/behdad.org/" target=3D"_blank">http://behdad.org/</a></div></div><br></div=
><br><div class=3D"gmail_quote gmail_quote_container"><div dir=3D"ltr" clas=
s=3D"gmail_attr">On Wed, Feb 25, 2026 at 9:24=E2=80=AFAM Alexei Podtelezhni=
kov &lt;<a href=3D"mailto:[email protected]">[email protected]</a>&gt; wr=
ote:<br></div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px=
 0.8ex;border-left:1px solid rgb(204,204,204);padding-left:1ex">Behdad,<br>
<br>
&gt; With help from my AI assistants, I finally put together a rasterizer i=
n HarfBuzz, in a new harfbuzz-raster library. Accompanying the rasterizer i=
s a COLRv1 color-font renderer, but I like to focus on the rasterizer in th=
is email:<br>
<br>
Congratulations!<br>
<br>
&gt; While it was designed from scratch, the general algorithm is similar t=
o FreeType&#39;s, that is, a coverage based AA rasterizer. From there thoug=
h, different approaches are taken. The end result is that the code runs 2x =
or more faster than FreeType&#39;s in my testing.<br>
<br>
Do you mind dissecting the performance of your rasterizer a bit<br>
further with the perf counter? This would help to compare performance<br>
more carefully. For example,<br>
$ perf record bin/ftbench -f2 -s32 -bc tahoma.ttf<br>
$ perf report<br>
<br>
=C2=A0 26.49%=C2=A0 ftbench=C2=A0 libfreetype.so.6.20.4=C2=A0 [.] gray_rend=
er_line<br>
=C2=A0 19.30%=C2=A0 ftbench=C2=A0 libfreetype.so.6.20.4=C2=A0 [.] gray_set_=
cell<br>
=C2=A0 18.37%=C2=A0 ftbench=C2=A0 libfreetype.so.6.20.4=C2=A0 [.] gray_conv=
ert_glyph<br>
=C2=A0 =C2=A07.78%=C2=A0 ftbench=C2=A0 libfreetype.so.6.20.4=C2=A0 [.] TT_L=
oad_Simple_Glyph<br>
=C2=A0 =C2=A04.92%=C2=A0 ftbench=C2=A0 libfreetype.so.6.20.4=C2=A0 [.] gray=
_conic_to<br>
<br>
This shows how FreeType rasterizer spends its time at 32 ppem. After<br>
subtracting other activities, the curve and line integration is about<br>
40%, the pixel list management is 30%, the final sweep is 30%. I<br>
suspect that the linked list management is what you avoid at the<br>
expense of more memory usage, with a faster sweep too.<br>
<br>
&gt; I long had intuited that a tightly woven rasterizer code will perform =
really well, and this experiment seems to prove that. The code is very shor=
t (~1000 lines) and readable:<br>
&gt;<br>
&gt;=C2=A0 =C2=A0<a href=3D"https://github.com/harfbuzz/harfbuzz/blob/main/=
src/hb-raster-draw.cc" rel=3D"noreferrer" target=3D"_blank">https://github.=
com/harfbuzz/harfbuzz/blob/main/src/hb-raster-draw.cc</a><br>
<br>
Thanks,<br>
Alexei<br>
</blockquote></div>

--00000000000050c08e064bbdb73c--