10 ms·
Pathfinder, a fast GPU-based font rasterizer in Rust
- pcwalton 10y agoFor those seeing broken links for the graphs, please reload. Happy to answer any questions :)
- mmastrac 10y agoI'm impressed how easy it is to get started with a Rust project from zero. # brew install rust # cargo build --release # cargo run --release --example lorem-ipsum -- resources/tests/nimbus-sans/NimbusSanL-Regu.ttf It doesn't appear to generate text properly on my Mid 2014 Macbook, however. I ended up with what appeared to be a red channel from random GPU memory when I pressed the screenshot key.
- pcwalton 10y agoThanks for the report! Could you file a GitHub issue mentioning your graphics hardware (which you can get from System Profiler)? This is the kind of GPU driver issue I was hoping to be able to get wide coverage for. :)
- pimeys 10y agoDidn't work first with my Zenbook and Arch Linux, when using the Intel i915 GPU, but just trying again with primusrun using the Nvidia 620M just worked. The Intel just doesn't support modern enough OpenGL: thread 'main' panicked at 'called `Result::unwrap()` on an `Err` value: CompileFailed("Tessellation control shader", "0:11(10): error: GLSL 4.10 is not supported. Supported versions are: 1.10, 1.20, 1.30, 1.40, 1.50, 3.30, 1.00 ES, and 3.00 ES\n\u{0}")', /buildslave/rust-buildbot/slave/stable-dist-rustc-linux/build/src/libcore/result.rs:837 Very nice work and awesome to see so many interesting Rust projects popping out every week.
- pcwalton 10y ago> Didn't work first with my Zenbook and Arch Linux, when using the Intel i915 GPU, but just trying again with primusrun using the Nvidia 620M just worked. Cool! Great to see successful Linux compatibility :)
- moosingin3space 10y agoLooks like I'll have to wait for the new Mesa to land -- no support for GL > 3.3 on my Intel cards. When I get it, I'll let you know how it works on Intel.
- flukus 10y agoI started a project last night and ran into dependency hell because my distro's compiler was on version 1.14 instead of 1.15, so it's not always that easy.
- OJFord 10y agoUse rustup. https://www.rustup.rs https://www.rustup.rs
- flukus 10y agoI did. It's ok for now because the ecosystem is still maturing, but a system language will need to learn to live with the system, not be in it's own isolated world like ruby/python/Java.
- mmstick 10y agoActually, your distribution needs to learn to live with the world rather than isolating itself to a stagnant point in history. If it's going to ship Rust in the repository, it needs to ensure that it always ships the latest version. If it doesn't plan on doing that, it should ship rustup instead. Otherwise, there's very little point in shipping Rust as you'll limit yourself to only being able to compile older versions of software. Ain't nobody got time to manage multiple versions of the same project for the sake of system X and Y having different versions of the Rust compiler. The Rust ecosystem is able to make leaps and bounds on a regular basis precisely because we aren't limiting ourselves to ancient versions of the Rust compiler because the system we use isn't technologically savvy enough to keep up with the times. Rust basically follows the Internet age of development, whereas point release distributions are stuck in a metaphorical floppy disk era (and often times still use mailing lists). Rustup is a major tool for development because it allows us to keep our toolchains updated. It's used for obtaining nightly compilers, stable compilers, official documentation, rust source code for racer autocompletion, and various different types of targets, such as MUSL vs Glibc on Linux, or installing the Windows GNU toolchain on Linux for cross-compiling. And there's literally zero reason to not follow the latest Rust compiler. Rust follows the semantic versioning rules, which dictates that all of the 1.x.x release are backwards compatible with 1.0.0. Upgrading the compiler will bring no breaking changes, but it will bring improved performance and features.
- photojosh 10y agoAlso impressed; it really was that easy. MacBook Pro (Retina, 13-inch, Early 2015) w/ Intel Iris Graphics 6100 1536 MB Still on Yosemite 10.10.4
- gpm 10y agoIt's not an issue, but the `cargo build --release` line is redundant, `cargo run` will build the executable if it isn't already before running it.
- jwilm 10y agoThe blog post mentions integrating with WebRender as an alternative rasterizer on capable systems. Could performance of the GPU-based rasterizer ever get to the point that WebRender's glyph cache is no longer needed? After glancing quickly at the code, it looks like the lorem ipsum example renders to a texture atlas. Is that part of Pathfinder or just part of that example? I'm trying to understand whether managing the altas would be up to the application or Pathfinder. How does/will Pathfinder support ligatures?
- pcwalton 10y ago> Could performance of the GPU-based rasterizer ever get to the point that WebRender's glyph cache is no longer needed? I would like to try eliminating the frame-to-frame glyph cache. Doing so would reduce load on the texture atlas allocator, which can get slow as it's approximating an NP-complete problem. For me, Pathfinder can rerasterize the entire ASCII character set in 1.5ms or so (depending on the font size), which easily fits under the frame budget. > After glancing quickly at the code, it looks like the lorem ipsum example renders to a texture atlas. Is that part of Pathfinder or just part of that example? Pathfinder's API is based around the concept of an atlas in order to improve batching. Especially at small sizes it's a lot more efficient to render multiple glyphs all in one go without issuing separate draw calls for each one. There's nothing preventing you from making a separate "atlas" for each glyph if you want, though you'll pay some performance cost for this. > How does/will Pathfinder support ligatures? Ligatures are just glyphs like any other. If you want to use ligatures, you can run a full-featured OpenType shaper, like HarfBuzz or Core Text, on your text before sending the resulting glyphs to Pathfinder to be rendered.
- jwilm 10y agoThanks for the answers! > Pathfinder's API is based around the concept of an atlas in order to improve batching. And the result of a raster job is then coordinates in the Atlas? > Especially at small sizes it's a lot more efficient to render multiple glyphs all in one go without issuing separate draw calls for each one. Makes sense > There's nothing preventing you from making a separate "atlas" for each glyph if you want, though you'll pay some performance cost for this. It's not exactly an atlas then is it :P. Sorry if I wasn't clear; I was trying to understand whether the library or the application is managing the Atlas. Sounds like the library.
- losvedir 10y agoPlease forgive the stupid question, since I don't know low level coding too well but: what are some uses of this? It says it's a "Rust library for OpenType font rendering" - so since it's a library that means other rust code can use it for their purposes. So might this someday find its way into Servo? Is it possible for other languages to take advantage of this, too?
- pcwalton 10y ago> So might this someday find its way into Servo? Yes, as the blog post states one of the immediate next goals is to hook this up to WebRender. WebRender is the 2D graphics backend for Servo. > Is it possible for other languages to take advantage of this, too? Yes, if bindings are written.
- robert_foss 10y agoAre there any plans for a CPU based render path? I can see it being quite handy from a developers point of view to have both rolled into the same library. Especially considering how much performance is left on the table with CPU architecture specific instructions like AVX2.
- pcwalton 10y agoMaybe. There are no immediate plans for it, but depending on the performance it might be worth adding.
- jarjoura 10y agoI'd be curious to see how this compares to CoreText on Mac and DirectWrite on Windows. Both are highly tuned for their respective platform so I'd see them as baseline.
- pcwalton 10y agoI haven't been able to find documentation from Microsoft as to which algorithm DirectWrite uses, but if it's the same as the algorithm Direct2D uses for general path rendering it has an expensive CPU-side tessellation step first and so has the typical drawbacks of long setup times. I wouldn't be surprised if DirectWrite does the actual path rendering on the CPU, like Skia does in typical configurations. Core Text (really, Core Graphics) renders paths on CPU. I benchmarked it and it generally performed a bit worse than stb_truetype.
- CalChris 10y agoAlong these lines, well, in parallel and a few doors down, there's Alacritty, a GPU-Accelerated Terminal Emulator written in Rust. https://github.com/jwilm/alacritty https://github.com/jwilm/alacritty
- pcwalton 10y agoIt would be interesting to connect Pathfinder to Alacritty. They accelerate two different things: Pathfinder accelerates the glyph rasterization (converting the vector outlines to bitmaps), while Alacritty accelerates the glyph compositing (blitting the bitmaps onto the screen).
- kevindqc 10y agoWould it change much? I imagine Alacritty doesn't rasterize the same glyphs over and over if they repeat and keeps some kind of Atlas, so using Pathfinder would just give a boost when creating that Atlas, which in the grand scheme of thing wouldn't change much?
- moosingin3space 10y agoI'd expect the most visible improvements would be on screens full of CJK characters, based on what the original font-rs announcement's graphs showed.
- pcwalton 10y agoYeah, if you aren't (a) using CJK text or similar or (b) zooming your terminal I don't expect it to change a lot.
- flukus 10y ago"The simplicity goal means that it doesn't have many features like tabs or scroll back as in other terminals." It's easy to be faster when you do less.
- OJFord 10y ago
- outworlder 10y ago> This is the case on the Mac, since Apple has not implemented any OpenGL features newer than OpenGL 4.2 (2011) sigh Once upon a time, the Mac was a great development platform...
- wmf 10y agoI bet it's great if you use Metal.
- robert_foss 10y agoLet's not encourage the continued existence of metal. More vendor lock in on Apple platforms is hardly needed nor a positive thing.
- johncolanduoni 10y agoEh, I can't blame them terribly for introducing it. It was pre-Vulkan so they didn't have any open options when it came to a DX12/Vulkan-level graphics API. There's a Vulkan-on-Metal implementation[1], and I'd have absolutely no complaints about the platform if there was simply an open source equivalent (well, maybe geometry shaders). [1]: https://moltengl.com/ https://moltengl.com/
- gsnedders 10y agoGiven Vulkan is in some ways lower-level than Metal, AIUI, surely there's a significant cost that would make targetting Metal directly a better solution for things performance-critical?
- johncolanduoni 10y agoMost of the critical low level of components of Vulkan are there: multiple command queues with manual synchronization, resource heaps (although they are optional for Metal), mixed compute/render support. Mostly Metal simplifies some of the distinctions Vulkan drivers may dump on the user: for example, Metal has only one command queue type while a Vulkan driver may force the user to manage several. The biggest hurdle I can think of is geometry/tesselation shaders. Newer versions of Metal support tesselation shaders, but they work rather differently than Vulkan's (they're based on a compute shader, instead of the Hull/Domain split other APIs use). Geometry shaders aren't supported at all.
- raphlinus 10y agoVery happy to see this become public, and it looks very impressive. I'm blushing a bit. Patrick and I indeed had very stimulating conversations, but all the hard work figuring out how to map rendering efficiently to a GPU is Patrick's.
- sushidev 10y agoCouldn't run the example on Ubuntu 16.10 Would appreciate anyone's help to get it running: ~/dev/rust/pathfinder$ cargo run --release --example lorem-ipsum -- resources/tests/nimbus-sans/NimbusSanL-Regu.ttf Downloading clap v2.20.3 Downloading image v0.12.3 Downloading bencher v0.1.2 Downloading quickcheck v0.4.1 Downloading semver v0.2.3 Downloading glfw-sys v3.2.1 Downloading enum_primitive v0.1.1 Downloading nom v1.2.4 Downloading cmake v0.1.20 Downloading gcc v0.3.43 Downloading vec_map v0.6.0 Downloading unicode-segmentation v1.1.0 Downloading ansi_term v0.9.0 Downloading unicode-width v0.1.4 Downloading term_size v0.2.2 Downloading strsim v0.6.0 Downloading gif v0.9.0 Downloading glob v0.2.11 Downloading png v0.6.2 Downloading scoped_threadpool v0.1.7 Downloading jpeg-decoder v0.1.11 Downloading color_quant v1.0.0 Downloading lzw v0.10.0 Downloading inflate v0.1.1 Downloading deflate v0.7.4 Downloading adler32 v0.3.0 Downloading rayon v0.6.0 Downloading deque v0.3.1 Downloading num_cpus v1.2.1 Downloading env_logger v0.3.5 Downloading regex v0.1.80 Downloading aho-corasick v0.5.3 Downloading thread_local v0.2.7 Downloading regex-syntax v0.3.9 Downloading memchr v0.1.11 Downloading utf8-ranges v0.1.3 Downloading thread-id v2.0.0 Compiling adler32 v0.3.0 Compiling utf8-ranges v0.1.3 Compiling ansi_term v0.9.0 Compiling color_quant v1.0.0 Compiling term_size v0.2.2 Compiling enum_primitive v0.1.1 Compiling lzw v0.10.0 Compiling scoped_threadpool v0.1.7 Compiling bencher v0.1.2 Compiling winapi-build v0.1.1 Compiling inflate v0.1.1 Compiling unicode-width v0.1.4 Compiling unicode-segmentation v1.1.0 Compiling glob v0.2.11 Compiling nom v1.2.4 Compiling gif v0.9.0 Compiling num-integer v0.1.32 Compiling rand v0.3.15 Compiling memchr v0.1.11 Compiling aho-corasick v0.5.3 Compiling regex-syntax v0.3.9 Compiling deflate v0.7.4 Compiling gcc v0.3.43 Compiling semver v0.2.3 Compiling strsim v0.6.0 Compiling deque v0.3.1 Compiling winapi v0.2.8 Compiling num_cpus v1.2.1 Compiling vec_map v0.6.0 Compiling lord-drawquaad v0.1.0 (https://github.com/pcwalton/lord-drawquaad.git#171a2507) Compiling num-iter v0.1.32 Compiling kernel32-sys v0.2.2 Compiling clap v2.20.3 Compiling num-complex v0.1.35 Compiling thread-id v2.0.0 Compiling thread_local v0.2.7 Compiling num-bigint v0.1.35 Compiling rayon v0.6.0 Compiling cmake v0.1.20 Compiling jpeg-decoder v0.1.11 Compiling num-rational v0.1.35 Compiling num v0.1.36 Compiling glfw-sys v3.2.1 error: failed to run custom build command for `glfw-sys v3.2.1` process didn't exit successfully: `/home/mich/dev/rust/pathfinder/target/release/build/glfw-sys-66de5311db1a83bd/build-script-build` (exit code: 101) --- stdout running: "cmake" "/home/mich/.cargo/registry/src/github.com-1ecc6299db9ec823/glfw-sys-3.2.1/." "-DGLFW_BUILD_EXAMPLES=OFF" "-DGLFW_BUILD_TESTS=OFF" "-DGLFW_BUILD_DOCS=OFF" "-DCMAKE_INSTALL_PREFIX=/home/mich/dev/rust/pathfinder/target/release/build/glfw-sys-79c50ef4a5edfcd6/out" "-DCMAKE_C_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_C_COMPILER=/usr/bin/cc" "-DCMAKE_CXX_FLAGS= -ffunction-sections -fdata-sections -fPIC -m64" "-DCMAKE_CXX_COMPILER=/usr/bin/c++" "-DCMAKE_BUILD_TYPE=Release" -- The C compiler identification is GNU 6.2.0 -- Check for working C compiler: /usr/bin/cc -- Check for working C compiler: /usr/bin/cc -- works -- Detecting C compiler ABI info -- Detecting C compiler ABI info - done -- Detecting C compile features -- Detecting C compile features - done -- Looking for pthread.h -- Looking for pthread.h - found -- Looking for pthread_create -- Looking for pthread_create - not found -- Looking for pthread_create in pthreads -- Looking for pthread_create in pthreads - not found -- Looking for pthread_create in pthread -- Looking for pthread_create in pthread - found -- Found Threads: TRUE -- Could NOT find Vulkan (missing: VULKAN_LIBRARY VULKAN_INCLUDE_DIR) -- Using X11 for window creation -- Configuring incomplete, errors occurred! See also "/home/mich/dev/rust/pathfinder/target/release/build/glfw-sys-79c50ef4a5edfcd6/out/build/CMakeFiles/CMakeOutput.log". See also "/home/mich/dev/rust/pathfinder/target/release/build/glfw-sys-79c50ef4a5edfcd6/out/build/CMakeFiles/CMakeError.log". --- stderr CMake Error at /usr/share/cmake-3.5/Modules/FindX11.cmake:439 (message): Could not find X11 Call Stack (most recent call first): CMakeLists.txt:192 (find_package) thread 'main' panicked at ' command did not execute successfully, got: exit code: 1 build script failed, must exit now', /home/mich/.cargo/registry/src/github.com-1ecc6299db9ec823/cmake-0.1.20/src/lib.rs:573 note: Run with `RUST_BACKTRACE=1` for a backtrace. Build failed, waiting for other jobs to finish... error: build failed
- ori_b 10y agoIt looks like this doesn't handle hinting, subpixel rendering, and glyph tweaks that people expect from modern font renderers. Hinting is not obsolete.
- pcwalton 10y agoI cover this at the end of the article. Hinting is generally just a transformation applied to the glyph outlines before rasterization; it doesn't affect the vector graphics renderer itself. Adding hinting would not cause problems for the algorithm. (I personally consider hinting obsolete, but I would rather not argue about it.) I'm not sure what you mean by "subpixel rendering". If you mean subpixel positioning, that is correctly handled, though not fully exposed in the API yet. If you mean subpixel AA, that is straightforward to add, and I expect it to improve performance relative to the CPU rasterizers by effectively tripling the glyph area.
- ghusbands 10y agoIf you do add subpixel AA, please make it optional. Some people, like me, can directly see the colour artifacts from it, even on hi-DPI displays. And others have multiple displays with differing orientation or pixel layout.
- jahewson 10y agoWatch out because some CJK fonts from Microsoft require hinting to render correctly. They are made up of composite glyphs where each sub-glyph corresponds to a brush stroke and hinting is used to scale and position them. More details here: https://blog.idrsolutions.com/2011/10/truetype-hinting-big-screens-for-small-details/ https://blog.idrsolutions.com/2011/10/truetype-hinting-big-s...
- JoshTriplett 10y ago> (I personally consider hinting obsolete, but I would rather not argue about it.) That depends heavily on your preferences in font rendering, and in particular whether you prefer Apple-style "accurate shapes with no respect for pixel alignment" or Windows-style "monitors have pixels, better to ignore the designer and snap to pixels than to be blurry" rendering. It also depends on the fonts you use; some fonts don't need hinting to look good, while others do.
- AceJohnny2 10y agoThis is an exciting demonstration, but I have one worry that's unaddressed: I'm assuming all the other nitpicky details of hinted font rendering etc is handled correctly by all the renderers compared? I mean, they all provide pixel-identical output? Otherwise the point is mostly useless. A faster rendering implementation is almost useless if the output doesn't look as nice. I wouldn't care if the text I'm reading over 5 minutes takes 200ms vs 800ms to render.
- leni536 10y agoI think one can mix hinters and renderers from different libraries. If it's all about fast vector rendering I don't see why they couldn't just use freetype's hinter (maybe they do).
- a_e_k 10y agoYou can. For my programming font [0], I provide versions of it that bake in the output from Freetype's hint interpreter applied at different point sizes and display DPIs. This way platforms such as macOS that don't always apply hinting can show it as though they did. [0] http://eastfarthing.com/luculent/ http://eastfarthing.com/luculent/
- pcwalton 10y agoPathfinder's rendering is best-in-class, equaling or exceeding the quality of the other renderers. FreeType, stb_truetype, font-rs, and Pathfinder all use exact trapezoidal area calculations for antialiasing. Most GPU algorithms use lower-quality multisample antialiasing, but matching the system renderer in quality is one of the key goals of Pathfinder. Regarding hinting, hinting is mostly a transformation applied to the vectors before rasterization, so it's (again, mostly) independent of the actual vector rasterizer. Note that many systems do no hinting at all. To make the benchmarks fair, hinting was disabled for the libraries that support it.
- ComputerGuru 10y agoHaving done some work that involved comparing a number of text rendering libraries in the past, I'm aware of the minute differences in rendering and hinting (even when the output should be the same). Could you briefly mention how hinting here would compare to ClearType?
- hesdeadjim 10y agoWonder how it compares to using Antigrain Geometry. I once had to implement text rendering in a game engine a bunch of years back and I used FreeType to load font glyphs and then fed the geometry data into Antigrain and had it rasterize (FreeType rasterization is meh while AGG is heavenly). Even on very old iPhone hardware I was able to render in the main update loop and not encounter any frame rate hiccups. Unfortunately AGG 2.5 is now GPL so if you need to stick it into anything closed source you are stuck using 2.4's modified BSD.
- kevin_thibedeau 10y ago2.5 is basically the same as 2.4 and is effectively dead since all new work has been going into the 2.4 branch.
- vvanders 10y agoFirst off, impressive stuff. That said I think having a CPU tessellation path is going to be critical if you want to see wide adoption. Platforms like Android and the like don't always have geo shaders which is why you see FreeType so widely used.
- pcwalton 10y agoYou need not only geometry/tess shaders but also compute shader and signed framebuffers. In theory it would be possible to work around the lack of compute shader (making the minimum requirement GLES 3.0), but it would involve multiple passes and I'm not optimistic about the performance in that case.
- vvanders 10y agoYeah, you just cut out half of android with those requirements. If I were ever to use it in production I'd def want a 2-tier system that works with older hardware and does the texture generation CPU side.
- ComputerGuru 10y agoI did some work a while back that involved using genetic algorithms to solve a problem pertaining to PC errors. Long story short, the bottleneck ended up being the generation of an error screen (which is then compared to a pre-existing one in the cost algorithm). We were first using GDI (on Windows), but then we switched to DirectWrite, but couldn't get it to be fast enough to make the algorithm feasible. This definitely piqued my interest!
- Mithaldu 10y agoHow easy would it be to integrate this with projects written primarily in other languages?
- pcwalton 10y agoIt should be straightforward if someone steps up to write the C bindings.
- moosingin3space 10y agoWas there someone working on a reverse-bindgen for cases like this? Thought I saw a project named in the Roadmap.
- deleted 10y ago[deleted]
- AriaMinaei 10y agoI wonder how this compares to the parallel vector rendering engine that Alan Kay has mentioned in a few of his talks [1][2]. [1]: https://youtu.be/XnDYuQUN4J0?t=1060 https://youtu.be/XnDYuQUN4J0?t=1060 [2]: https://github.com/damelang/nile https://github.com/damelang/nile
- datenwolf 10y agoImpressive work. One of my (far too many) ongoing projects, is also a GPU based glyph renderer. However I'm using a different method, which relies on some preprocessing/conversion of the glyph data. Described in as few words as possible my method could be coined as "trivariate polynomial distance fields". The renderer is mostly done, but there's still a lot of work needed in the glyph preprocessor to be robust and universally usable. Months ago I posted a few screenshots on Twitter (https://twitter.com/datenwolf/status/714934185564225536 https://twitter.com/datenwolf/status/714934185564225536), and the comment by Michael IV is spot on. The renderer has no problem with sharp corners, but so far the glyph preprocessor still struggles with it and I have to manually adjust the emitted output to get nice results.
- fmap 10y agoThis looks impressive, but does anybody know why "exact coverage" is apparently considered the gold standard for rendering vector graphics? Mathematically, computing pixel coverage corresponds to sampling a box filtered version of a characteristic function. In practice I would expect, say, a gaussian filter to be both easier to approximate and less prone to aliasing artifacts. Apparently that expectation is completely wrong though, since nobody seems to implement it that way! What's so special about vector graphics that makes the box filter behave well?
- vedranm 10y agoThanks for posting this. Added to [1]. Will try running it on Mesa radeonsi OpenGL and OpenCL later. [1] https://en.wikipedia.org/wiki/List_of_OpenCL_applications https://en.wikipedia.org/wiki/List_of_OpenCL_applications
- tokyovigilante 10y agoAPI wars aside, is anyone interested in contributing to a Swift/Metal port? A Rust library isn't particularly portable to iOS.