Pathfinder, a fast GPU-based font rasterizer in Rust
pcwalton.github.io
pcwalton.github.io
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.
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.
Between that and clipping paths, I've been thinking of sticking with multisampling, as nice as the exactness of the trapezoidal algorithm can be.
I would recommend doing the trapezoidal area approach in spite of these limitations. Having 256 shades of gray instead of 8 or so makes a big difference for all paths, not just pathological ones. It often ends up faster than MSAA, too.
I wonder if this is even possible once you move it to the GPU. Reading about some of the fingerprinting methods in browsers lately, many rely on different GPU's doing different things with the same input.
Different GPUs should produce pixel-identical output. If not, it's a bug either in Pathfinder or the driver.
The number of teams I've seen pursue golden-image tests on GPU pipelines and fail has been 100%(4/4).
I probably shouldn't find this disturbing, but I do.
- Poorly defined APIs/types that allow vendors to diverge.
- Legit driver bugs.
- Vendors preferring optimizations to following the spec(including skipping memzero requirements).
- Hardware that doesn't behave how it should(fp32 falling back to fp16 silently for instance).
Overall you don't really win any points in the market for correctness, instead performance and efficiency are highly valued.sigh
Once upon a time, the Mac was a great development platform...
Node is my current dev environment of choice, but I'm mostly doing service level things or web-based applications. So it fits well for that use case. Of course it also shapes my choices if I did do desktop stuff as I'd more likely reach for ReactNative or Electron. Even if I'm very interesting in getting my feet wet with go and rust.
It still is.
XCode, Cocoa Frameworks, Swift, Objective-C, Instruments are there and doing great.
I don't care one second about UNIX underpinnings.
More vendor lock in on Apple platforms is hardly needed nor a positive thing.
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).
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.
Most people doing graphics have to implement an abstraction layer anyway for handling DirectX, vulkan or old OpenGL.
Once you have it, it is not so much work adding one additional back end.
I now believe competition is great and one of the things that made Europe for example to prosper while China stagnated for 5 centuries.
If you say for example: "We only support text shaders because it is simple and works well enough" and someone else uses and API or DOM and it goes 200 times faster, I want the option to let the first guys down and pick the 200X improvement version, not having to stand the original "because it is the standard and we don't care".
Yes, it is. I would have been able to develop Pathfinder a lot faster if I didn't have to write and debug the "compute-shader" abstraction.
> If you say for example: "We only support text shaders because it is simple and works well enough" and someone else uses and API or DOM and it goes 200 times faster, I want the option to let the first guys down and pick the 200X improvement version, not having to stand the original "because it is the standard and we don't care".
Vulkan exposes more of the hardware than Metal does. Having separate tessellation evaluation/tessellation control shaders is important to the way that Pathfinder works.
It's one thing to have a vendor-specific API that's better than the standard. It's quite another to have a vendor-specific API that's worse...
This basically sums it up regarding my lost years with OpenGL.
If anything, Apple needs competition with themselves. There's no route to a modern graphics API on macOS (or iOS for that matter).
Vulcan is unsupported
Where? Windows, Linux, Andriod, Intel, AMD, and Nvidia have rolled out supportApple is the only people who haven't because of Metal.
Windows support is done by GPU vendors, not Microsoft and is only supported on Win32, not UWP applications.
Sony doesn't plan to support Vulkan, PS* APIs are much better.
Nintendo did introduce support for the Switch, but they are so confident on it, that they also have NVN, which offers much better control over the hardware.
> NVN, which offers much better control over the hardware.
Can you cite specific reasons? Vulkan is about as low-level as you can go.
https://blogs.nvidia.com/blog/2016/10/20/nintendo-switch/
"NVIDIA additionally created new gaming APIs to fully harness this performance. The newest API, NVN, was built specifically to bring lightweight, fast gaming to the masses."
The rest is behind the SDKs NDA.
They've gotten partway there with things like D3D12 descriptor heaps, but hardware-specific APIs just don't have those limitations.
It isn't cross-platform, so it lacks the most important of all of Vulkan's features.
However, I can't help but seeing it modeled on the Direct X vendor lock-in model that starved Apple of games (and users because of those games). While it may not be a sign of change in Apple, it is a sign to me I shouldn't depend on them to provide products that meet my needs as a cross-platform developer. All those years I invested in a neglected OpenGL I should have devoted instead to directx; perhaps I would be less bitter now.
But from the documentation, it looks like quite a nice and simple API that also exposes the modern capabilities of shaders. It would probably make a great base for a new webgpu API.
This existence of Metal isn't really an issue. The real issue is that apple has silently shifted to a mode of only supporting Metal, not implementing vulkan and neglecting opengl.
Like this?
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?
It's easy to be faster when you do less.
> Instead, it is expected that users of Alacritty make use of a terminal multiplexer such as tmux.
Alacritty does one thing well. If you're using a terminal multiplexer or tiling window manager anyway, you're probably not using tabs; instead hoping there's a way to hide the 'tab bar' if only one is open. If you're using tmux, it has scrollback.
I've been using Alacritty without tmux or any other way of achieving scrollback, and I like it. The few times I've thought 'damn, I need to scroll back to that thing' it's because I should have done it differently anyway.
Happy to answer any questions :)
# 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.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.Cool! Great to see successful Linux compatibility :)
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.
MacBook Pro (Retina, 13-inch, Early 2015) w/ Intel Iris Graphics 6100 1536 MB Still on Yosemite 10.10.4
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?
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.
> 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.
Yes.
> 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.
The library manages the atlas, because it uses a particular packing algorithm that maximizes the performance of the accumulation step (by increasing parallelism) when rasterizing many glyphs at once.
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.
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.
Months ago I posted a few screenshots on Twitter (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.
Core Text (really, Core Graphics) renders paths on CPU. I benchmarked it and it generally performed a bit worse than stb_truetype.
Hinting is not obsolete.
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.
More details here:
https://blog.idrsolutions.com/2011/10/truetype-hinting-big-s...
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.
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.
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.
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.
[1]: https://youtu.be/XnDYuQUN4J0?t=1060 [2]: https://github.com/damelang/nile
[1] https://en.wikipedia.org/wiki/List_of_OpenCL_applications
~/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 sudo apt-get install libglfw3 libglfw3-devran this:
sudo apt-get install xorg-dev
and then this:
sudo apt-get install freeglut3 freeglut3-dev libglew1.5 libglew1.5-dev libglu1-mesa libglu1-mesa-dev libgl1-mesa-glx libgl1-mesa-dev
And that fixed the problem
unformatted text
including newlines