Hi there! This is a guest post from Robert Mader, who contributed enormous improvements to Firefox’s graphics stack on Linux. TL;DR In the upcoming Firefox 94 release we will enable the EGL backend for a big group of our Linux users. This will increase WebGL performance, reduce resource consumption and make our life as developers … Continue reading Switching the Linux graphics stack from GLX to EGL →
Hi there! This is a guest post from Robert Mader, who contributed enormous improvements to Firefox’s graphics stack on Linux.
TL;DR In the upcoming Firefox 94 release we will enable the EGL backend for a big group of our Linux users. This will increase WebGL performance, reduce resource consumption and make our life as developers easier going forward.
Background In order to use hardware accelerated APIs like OpenGL with windowing systems like X11 or Wayland there needs to be an interface bringing them together. For OpenGL on X11 most programs use GLX, while its successor, EGL, gets used on Wayland, Android and in the embedded space. While EGL has some major advantages compared to GLX and, in theory, can be used on X11 just as well, its adoption there has been very slow.
I can only speculate why exactly that is, but I think it comes down to the following reasons:
What changed?
Firefox is an application that benefits heavily from hardware acceleration in many areas. However, until recently, software rendering remained the default. It was only this year that finally Webrender, Firefox’s new rendering engine, got enabled for most Linux users.
There is a very long list of developments that made this step easier and thus possible. To name a few:
The last point was crucial for the topic of the post. When Martin Stránský implemented Wayland hardware acceleration support in Firefox, he could not reuse GLX code, but instead used the Android EGL one. From there, an interesting dynamic started.
Improving the EGL backend and sharing code Step by step, a number of improvements were made to the EGL/Wayland backend which had effects on other platforms as well:
This is just a very small extraction of examples and maybe it gives you an idea of what I’m trying to say: more and more code gets shared between Wayland, X11/EGL and Android. This improves code quality, increases available time to spend on features and bugs, reduces the maintenance burden – you name it.
Making EGL the default Over the last year, more and more user found out about the possibility to use EGL on X11 – likely because it’s a prerequisite for hardware video decoding. Lots of bugs got fixed in Firefox but also other components. Now we finally feel ready to let it ride the trains. As of Firefox 94, users using Mesa driver >= 21 will get it by default. Users of the proprietary Nvidia driver will need to wait a little bit longer as the currently released drivers lack an important extension. However, most likely we’ll be able to enable EGL on the 470 series onwards. DMABUF support (and thus better WebGL performance) requires GBM support and will be limited to the 495 series onwards.
Benefits for users So what exactly can you expect, and why? Mainly:
Special thanks There is long list of people who have contributed to this step. To name a few: Martin Stránský, Andrew Osmond, Jamie Nicol, Grep V, Jan Ikenmeyer (Darkspirit), Michel Dänzer, the Firefox GFX-Team, the Mesa project and contributors, the Nvidia drivers team, the GTK team.
Finally: thanks a lot to all users who filed bugs and helped us fix them!
About the author Hi, I’m Robert Mader, a free time FOSS contributor, mainly working on Firefox and Mutter/Gnome-Shell.
WebGPU is a new standard for graphics and computing on the Web. Our team is actively involved in the design and specification process, while developing an implementation in Gecko. We’ve made a lot of progress since the last public update in Mozilla Hacks blog, and we’d like to share!
WebGPU textured+lit cube in Firefox Nightly with WGSL shaders.
See full code in the fork.
API Tracing
Trouble-shooting graphics issues can be tough without proper tools. In WebRender, we have the capture infrastructure that allows us to save the state of the rendering pipeline at any given moment to disk, and replayed independently in a standalone environment. In WebGPU, we integrated something similar, called API tracing. Instead of slicing through the state at any given time, it records every command executed by WebGPU implementation from the start. The produced traces are ultimately portable, they can be replayed in a standalone environment on a different system. This infrastructure helps us breeze through the issues, fixing them quickly and not letting them stall the progress.
Rust Serialization Gecko implementation of WebGPU has to talk in multiple languages: WebIDL, in which the specification is written, C++ – the main language of Gecko, IPDL – the description of inter-process communication (IPC), and Rust, in which wgpu library (the core of WebGPU) is implemented. This variety caused a lot of friction when updating the WebIDL API to latest, it was easy to introduce bugs, which were hard to find later. This architectural problem has been mostly solved by making our IPC rely on Rust serde+bincode. This allows Rust logic on the content process side to communicate with Rust logic on the GPU process side with minimal friction. It was made possible by the change to Rust structures to use Cow types aggressively, which are flexible and efficient, even though we don’t use the “write” part of the copy-on-write semantics.
API Coverage * The W3C group has agreed on the CPU data transfers API of writeBuffer/writeTexture, as well as the new asynchronous buffer mapping semantics with mappedAtCreation flag. We implemented these in Gecko, using a bit of shared memory. * The group introduced a new simplified way of creating pipelines, using implicit bind group layouts. We also implemented this in Gecko, while keeping some of the concerns on the table. * There were major rewrites of the render pipeline API and bind group layouts, both of which landed in Gecko before they became available in other browsers. * Some of the pieces of the API are still not implemented, such as queries and render bundles.
Validation The API on the Web is required to be safe and portable, which is enforced by the validation logic. We’ve made a lot of progress in this area: wgpu now has a first-class concept of “error” objects, which is what normal objects become if their creation fails on the server side (the GPU process). We allow these error objects to be used by the content side, and at the same time it returns the errors to the GPU process C++ code, which routes them back to the content side. There, we are now properly triggering the “uncaptured error” events with actual error messages:
In a draw command, indexed:false indirect:false, caused by: vertex buffer 0 must be set
GPUValidationError
What this means for us, as well as the brave experimental users, is better robustness and safety, less annoying panics/crashes, and less time wasted on investigating issues. The validation logic is not yet comprehensive, there is a lot yet to be done, but the basic infrastructure is mostly in place. We validate the creation of buffers, textures, bind group layouts, pipelines, and we validate the encoded commands, including the compute and render pass operations. We also validate the shader interface, and we validate the basic properties of the shader (e.g. the types making sense). We even implement the logic to check the uniformity requirements of the control flow, ahead of the specification, although it’s new and fragile at the moment.
Shading Language WebGPU Shading Language, or WGSL for short, is a new secure shading language for the Web, targeting SPIR-V, HLSL, and MSL on the native platforms. It’s exceptionally hard to support right now because of how young it is. The screenshot above was rendered with WGSL shaders in Firefox Nightly, you can get a feel of it by looking at the code.
Our recent update carried basic support for WGSL, using Naga library. The main code path in Gecko right now involves the following stages:
Next Steps One of the areas of improvement here is related to SPIR-V. In the future, we don’t want to unconditionally route the shader translation through SPIR-V, and we don’t want to rely on SPIRV-Cross, which is currently a giant C++ dependency that is hard to secure. Instead, we want to generate the platform-specific shaders straight from Naga IR ourselves. This will drastically reduce the amount of code involved, cut down the dependencies, and make the shader generation faster and more robust, but it requires more work.
Another missing bit is shader sanitation. In order to allow shaders to execute safely on GPU, it’s not enough to enable the safety features of the underlying APIs. We also need to insert bound checks in the shader code, where we aren’t sure about resource bounds being respected. These changes will be very sensitive to performance of some of the heaviest GPU users, such as TFjs.
Most importantly, we need to start testing Gecko’s implementation on the conformance test suite (CTS) that is developed by WebGPU group. This would uncover most of the missing bits in the implementation, and will make it easier to avoid regressions in the near future. Hopefully, the API has stabilized enough today that we can all use the same tests.
Contributing There is a large community around the Rust projects involved in our implementation. We welcome anyone to join the fun, and are willing to mentor them. Please hop into a relevant Matrix room to chat:
WebGPU progress update in Gecko: API tracing, Rust serialization, API coverage, validation, and the Shading language.
This is going to be a rather technical dive into a recent improvement that went into WebRender.
Texture atlas allocation In order to submit work to the GPU efficiently, WebRender groups as many drawing primitives as it can into what we call batches. A batch is submitted to the GPU as a single drawing command and has a few constraints. for example a batch can only reference a fixed set of resources (such as GPU buffers and textures). So in order to group as many drawing primitives as possible in a single batch we need to place as many drawing parameters as possible in few resources. When rendering text, WebRender pre-renders the glyphs before compositing them on the screen so this means packing as many pre-rendered glyphs as possible into a single texture, and the same applies for rendering images and various other things.
For a moment let’s simplify the case of images and text and assume that it is the same problem: input images (rectangles) of various rectangular sizes that we need to pack into a larger textures. This is the job of the texture atlas allocator. Another common name for this is rectangle bin packing.
Many in game and web development are used to packing many images into fewer assets. In most cases this can be achieved at build time Which means that the texture atlas allocator isn’t constrained by allocation performance and only needs to find a good layout for a fixed set of rectangles without supporting dynamic allocation/deallocation within the atlas at run time. I call this “static” atlas allocation as opposed to “dynamic” atlas allocation.
There’s a lot more literature out there about static than dynamic atlas allocation. I recommend reading A thousand ways to pack the bin which is a very good survey of various static packing algorithms. Dynamic atlas allocation is unfortunately more difficult to implement while keeping good run-time performance. WebRender needs to maintain texture atlases into which items are added and removed over time. In other words we don’t have a way around needing dynamic atlas allocation.
A while back
A while back, WebRender used a simple implementation of the guillotine algorithm (explained in A thousand ways to pack the bin). This algorithm strikes a good compromise between packing quality and implementation complexity.
The main idea behind it can be explained simply: “Maintain a list of free rectangles, find one that can hold your allocation, split the requested allocation size out of it, creating up to two additional rectangles that are added back to the free list.”. There is subtlety in which free rectangle to choose and how to split it, but the overall, the algorithm is built upon reassuringly understandable concepts.
Deallocation could simply consist of adding the deallocated rectangle back to the free list, but without some way to merge back neighbor free rectangles, the atlas would quickly get into a fragmented stated with a lot of small free rectangles and can’t allocate larger ones anymore.
Lots of free space, but too fragmented to host large-ish allocations. To address that, WebRender’s implementation would regularly do a O(n²) complexity search to find and merge neighbor free rectangles, which was very slow when dealing with thousands of items. Eventually we stopped using the guillotine allocator in systems that needed support for deallocation, replacing it with a very simple slab allocator which I’ll get back to further down this post.
Moving to a worse allocator because of the run-time defragmentation issue was rubbing me the wrong way, so as a side project I wrote a guillotine allocator that tracks rectangle splits in a tree in order to find and merge neighbor free rectangle in constant instead of quadratic time. I published it in the guillotiere crate. I wrote about how it works in details in the documentation so I won’t go over it here. I’m quite happy about how it turned out, although I haven’t pushed to use it in WebRender, mostly because I wanted to first see evidence that this type of change was needed and I already had evidence for many other things that needed to be worked on.
The slab allocator What replaced WebRender’s guillotine allocator in the texture cache was a very simple one based on fixed power-of-two square slabs, with a few special-cased rectangular slab sizes for tall and narrow items to avoid wasting too much space. The texture is split into 512 by 512 regions, each region is split into a grid of slabs with a fixed slab size per region.
The slab allocator in action. This is a debugging view generated from a real browsing session.
This is a very simple scheme with very fast allocation and deallocation, however it tends to waste a lot of texture memory. For example allocating an 8×10 pixels glyph occupies a 16×16 slot, wasting more than twice the requested space. Ouch!
In addition, since regions can allocate a single slab size, space can be wasted by having a region with few allocations because the slab size happens to be uncommon.
Improvements to the slab allocator Images and glyphs used to be cached in the same textures. However we render images and glyphs with different shaders, so currently they can never be used in the same rendering batches. I changed image and glyphs to be cached into a separate set of textures which provided with a few opportunities.
Not mixing images and glyphs means the glyph textures get more room for glyphs which reduces the number of textures containing glyphs overall. In other words, less chances to break batches. The same naturally applies to images. This is of course at the expense of allocating more textures on average, but it is a good trade-off for us and we are about to compensate the memory increase by using tighter packing.
In addition, glyphs and images are different types of workloads: we usually have a few hundred images of all sizes in the cache, while we have thousands of glyphs most of which have similar small sizes. Separating them allows us to introduce some simple workload-specific optimizations.
The first optimization came from noticing that glyphs are almost never larger than 128px. Having more and smaller regions, reduces the amount of atlas space that is wasted by partially empty regions, and allows us to hold more slab sizes at a given time so I reduced the region size from 512×512 to 128×128 in the glyph atlases. In the unlikely event that a glyph is larger than 128×128, it will go into the image atlas.
Next, I recorded the allocations and deallocations browsing different pages, gathered some statistics about most common glyph sizes and noticed that on a low-dpi screen, a quarter of the glyphs would land in a 16×16 slab but would have fit in a 8×16 slab. In latin scripts at least, glyphs are usually taller than wide. Adding 8×16 and 16×32 slab sizes that take advantage of this helps a lot.
I could have further optimized specific slab sizes by looking at the data I had collected, but the more slab sizes I would add, the higher the risk of regressing different workloads. This problem is called over-fitting. I don’t know enough about the many non-latin scripts used around the world to trust that my testing workloads were representative enough, so I decided that I should stick to safe bets (such as “glyphs are usually small”) and avoid piling up optimizations that might penalize some languages. Adding two slab sizes was fine (and worth it!) but I wouldn’t add ten more of them.
The original slab allocator needed two textures to store a workload that the improved allocator can fit into a single one. At this point, I had nice improvements to glyph allocation using the slab allocator, but I had a clear picture of the ceiling I would hit from the fixed slab allocation approach.
Shelf packing allocators I already had guillotiere in my toolbelt, in addition to which I experimented with two algorithms derived from the shelf packing allocation strategy, both of them released in the Rust crate etagere. The general idea behind shelf packing is to separate the 2-dimensional allocation problem into a 1D vertical allocator for the shelves and within each shelf, 1D horizontal allocation for the items.
The atlas is initialized with no shelf. When allocating an item, we first find the shelf that is the best fit for the item vertically, if there is none or the best fit wastes too much vertical space, we add a shelf. Once we have found or added a suitable shelf, an horizontal slice of it is used to host the allocation.
At a glance we can see that this scheme is likely to provide much better packing than the slab allocator. For one, items are tightly packed horizontally within the shelves. That alone saves a lot of space compared to the power-of-two slab widths. A bit of waste happens vertically, between an item and the top of its shelf. How much the shelf allocator wastes vertically depends on how the shelve heights are chosen. Since we aren’t constrained to power-of-two size, we can also do much better than the slab allocator vertically.
The bucketed shelf allocator The first shelf allocator I implemented was inspired from Mapbox’s shelf-pack allocator written in JavaScript. It has an interesting bucketing strategy: items are accumulated into fixed size “buckets” that behave like a small bump allocators. Shelves are divided into a certain number of buckets and buckets are only freed when all elements are freed. The trade-off here is to keep atlas space occupied for longer in order to reduce the CPU cost of allocating and deallocating. Only the top-most shelf is removed when empty so consecutive empty shelves in the middle aren’t merged until they become the top-most shelves, which can cause a bit of vertical fragmentation for long running sessions. When the atlas is full of (potentially empty) shelves the chance that a new item is too tall to fit into one of the existing shelves depends on how common the item height is. Glyphs tend to be of similar (small) heights so it works out well enough.
I added very limited support for merging neighbor empty shelves. When an allocation fails, the atlas iterates over the shelves and checks if there is a sequence of empty shelves that in total would be able to fit the requested allocation. If so, the first shelf of the sequence becomes the size of the sum, and the other shelves are squashed to zero height. It sounds like a band aid (it is) but the code is simple and it is working within the constraints that make the rest of the allocator very simple and fast. It’s only a limited form of support for merging empty shelves but it was an improvement for workloads that contain both small and large items.
Image generated from the glyph cache in a real borwsing session via a debugging tool. We see fewer/wider boxes rather than many thin boxes because the allocator internally doesn’t keep track of each item rectangle individually, so we only see buckets filling up instead. This allocator worked quite well for the glyph texture (unsurprisingly, as Mapbox’s implementation it was inspired from is used with their glyph cache). The bucketing strategy was problematic, however, with large images. The relative cost of keeping allocated space longer was higher with larger items. Especially with long running sessions, this allocator was good candidate for the glyph cache but not for the image cache.
The simple shelf allocator The guillotine allocator was working rather well with images. I was close to just using it for the image cache and move on. However, having spent a lot of time looking at various allocations patterns, my intuition was that we could do better. This is largely thanks to being able to visualize the algorithms via our integrated debugging tool that could generate nice SVG visualizations.
It motivated experimenting with a second shelf allocator. This one is conceptually even simpler: A basic vertical 1D allocator for shelves with a basic horizontal 1D allocator per shelf. Since all items are managed individually, they are deallocated eagerly which is the main advantage over the bucketed implementation. It is also why it is slower than the bucketed allocator, especially when the number of items is high. This allocator also has full support for merging/splitting empty shelves wherever they are in the atlas.
This was generated from the same glyph cache wokrload as the previous image. Unlike the Bucketed allocator, this one worked very well for the image workloads. For short sessions (visiting only a handful of web pages) it was not packing as tightly as the guillotine allocator, but after browsing for longer period of time, it had a tendency to better deal with fragmentation.
The simple shelf allocator used on the image cache. Notice how different the image workloads look (using the same texture size), with much fewer items and a mix of large and small items sizes. The implementation is very simple, scanning shelves linearly and then within the selected shelf another linear scan to find a spot for the allocation. I expected performance to scale somewhat poorly with high number of glyphs (we are dealing in the thousands of glyphs which arguably isn’t that high), but the performance hit wasn’t as bad I had anticipated, probably helped by mostly cache friendly underlying data-structure.
A few other experiments For both allocators I implemented the ability to split the atlas into a fixed number of columns. Adding columns means more (smaller) shelves in the atlas, which further reduces vertical fragmentation issues, at the cost of wasting some space at the end of the shelves. Good results were obtained on 2048×2048 atlases with two columns. You can see in the previous two images that the shelf allocator was configured to use two columns.
The shelf allocators support arranging items in vertical shelves instead of horizontal ones. It can have an impact depending on the type of workload, for example if there is more variation in width than height for the requested allocations. As far as my testing went, it did not make a significant difference with workloads recorded in Firefox so I kept the default horizontal shelves.
The allocators also support enforcing specific alignments in x and y (effectively, rounding up the size of allocated items to a multiple of the x and y alignment). This introduces a bit of wasted space but avoids leaving tiny holes in some cases. Some platforms also require a certain alignment for various texture transfer operations so it is useful to have this knob to tweak at our disposal. In the Firefox integration, we use different alignments for each type of atlas, favoring small alignments for atlases that mostly contain small items to keep the relative wasted space small.
Conclusion Various visualizations generated while I was working on this. It’s been really fun to be able “look” at the algorithms at each step of the process. The guillotine allocator is the best at keeping track of all available space and can provide the best packing of the algorithms I tried. The shelf allocators waste a bit of space by simplifying the arrangement into shelves, and the slab allocator wastes a lot of space for the sake of simplicity. On the other hand the guillotine allocator is the slowest when dealing with multiple thousands of items and can suffer from fragmentations in some of the workloads I recorded. Overall the best compromise was the simple shelf allocator which I ended up integrating in Firefox for both glyph and image textures in the cache (in both cases configured to have two columns per texture). The bucketed allocator is still a very reasonable option for glyphs and we could switch to it in the future if we feel we should trade some packing efficiency for allocation/deallocation performance. In other parts of WebRender, for short lived atlases (a single frame), the guillotine allocation algorithm is used.
These observations are mostly workload-dependent, though. Workloads are rarely completely random so results may vary.
There are other algorithms I could have explored (and maybe will someday, who knows), but I had found a satisfying compromise between simplicity, packing efficiency, and performance. I wasn’t aiming for state of the art packing efficiency. Simplicity was a very important parameter and whatever solutions I came up with would have to be simple enough to ship it in a web browser without risks.
To recap, my goals were to:
This was achieved by improving atlas packing to the point that we more rarely have to allocate multiple textures for each item type . The results look pretty good so far. Before the changes in Firefox, glyphs would often be spread over a number of textures after having visited a couple of websites, Currently the cache eviction is set so that we rarely need more than than one or two textures with the new allocator and I am planning to crank it up so we only use a single texture. For images, the shelf allocator is pretty big win as well. what used to fit into five textures now fits into two or three. Today this translates into fewer draw calls and less CPU-to-GPU transfers which has a noticeable impact on performance on low end Intel GPUs, in addition to reducing GPU memory usage.
The slab allocator improvements landed in bug 1674443 and shipped in Firefox 85, while the shelf allocator integration work went in bug 1679751 and will make it hit the release channel in Firefox 86. The interesting parts of this work are packaged in a couple of rust crates under permissive MIT OR Apache-2.0 license:
guillotiere (crate) (doc)
etagere (crate) (doc)
This is going to be a rather technical dive into a recent improvement that went into WebRender. Texture atlas allocation In order to submit work to the GPU efficiently, WebRender groups as many drawing primitives as it can into what we call batches. A batch is submitted to the GPU as a single drawing command … Continue reading Improving texture atlas allocation in WebRender →
Hey all, Jim Mathies here, the new Mozilla Graphics Team manager. We haven’t had a Graphics Newsletter since July, so there’s lots to catch up on. TL/DR – We’re shipping our Rust based WebRender backend to a very wide audience as of Firefox 84. Read on for more detail on our progress. WebRender Current Status … Continue reading moz://gfx newsletter #54 →
Hey all, Jim Mathies here, the new Mozilla Graphics Team manager. We haven’t had a Graphics Newsletter since July, so there’s lots to catch up on. TL/DR – We’re shipping our Rust based WebRender backend to a very wide audience as of Firefox 84. Read on for more detail on our progress.
WebRender Current Status
The release audience for WebRender has expanded quite a bit over the last six months. As a result we expect to achieve nearly 80% desktop coverage by the end of the year and have a goal of shipping to 100% of our user base by next summer.
Operating System Support
MacOS – As of Firefox 84, we are shipping to all versions of MacOS including the latest Big Sur release.
Windows 10 – We are currently shipping to all versions of Windows 10.
Windows 8/8.1 – We are currently shipping to all versions of Windows 8.
Windows 7 – We are currently shipping to a subset of Windows 7 users. Users currently excluded are running versions of the operating system which have not received the first major platform update. Prior to this update Windows 7 lacked features WebRender relies on for painting to a window managed by a separate process. We are working on adding a fallback mechanism that moves composition into the parent browser process to work around this. We hope to ship support for this fallback mechanism in Firefox 85.
Android – We are currently shipping to devices that leverage the Mali-G chipset, Pixel devices, and a majority of Adreno 5 and 6 devices. Mali-T GPUs are our next big release target. Once we get Mali-T support out the door, we’ll have achieved 70% coverage for our mobile user base.
Linux – We have a little announcement to make here, in Firefox 84 will ship with an accelerated WebRender backend for the first time ever to a subset of Linux users. The target cohort leverages X11, Gnome, and recent Mesa library versions. We plan to expand this rollout to more desktop configurations over time, stay tuned!
Qualified Hardware
A note about qualified hardware – we have the ability to restrict who received the new pipeline based on a combination of hardware parameters – GPU manufacturer, generation, driver versions, battery power, video refresh rate, dual monitor configurations, and even screen size. We leveraged these filters heavily during our initial rollout to target specific cohorts. Thankfully most of these filters are no longer in use as our target audience has expanded greatly over the last six months.
As of Firefox 83, we are shipping to a majority of nVidia and AMD GPUs, and to all Intel GPUs newer than Generation 6. We actually shipped to Generation 6 GPUs in 83 but had to back off when some users reported rendering glitches on Reddit. The fix for this issue landed in 85 and has since been uplifted to 84 for rollout to Release, bringing WebRender support to the vast majority of modern Intel chipsets in Firefox 84.
The remaining GPUs we plan to target include older Intel Generation 4.5 and 5, a batch of mobile specific ‘LP’ Intel chipsets, and various older AMD/ATI/nVidia chipsets that represent the long tail of compatible chipsets from these manufacturers.
If you’re curious to see if your device is qualified and running with the new pipeline, visit about:support in a tab and view the Graphics section for this information.
The Long Tail
WebRender is an accelerated rendering backend. This means we leverage the power of your graphics hardware to speed getting pixels to the screen. Unfortunately there are some hardware configurations which will never be able to support this type of rendering pipeline. That’s a problem in that without 100% WebRender coverage for the Firefox user base, we’ll never be able to remove the old pipelining code these users leverage today. Our solution here involves a new fallback mechanism that performs rendering in software. Since WebRender currently supports an OpenGL based hardware backend, software fallback is essentially a software implementation of certain OpenGL ES3 features tailored for WebRender support. We’ve recently started testing software fallback in Nightly and are seeing better than expected performance. We’re not ready to ship this implementation yet but we’re getting closer. Once ready, software fallback will provide WebRender support to the ‘long tail’ of lower-end hardware, uncommon configurations, and users with specific issues like bad drivers.
Shipping software fallback will allow us to close the loop on 100% WebRender coverage, at which point the Graphics Team can move forward on new and interesting projects we’ve been itching to get too for a while now.
WebGPU
Independent of WebRender rollout we are continuing our work on Firefox’s WebGPU implementation currently available for testing in Nightly builds. The specification is on track to reach MVP status in the near future, after which it will go through a period of feedback and change on the road to the release of the final specification sometime in 2021.
Looking Beyond WebRender
WebRender development and shipping has taken a few years to accomplish. We’re finally at a point where the team is starting to think about what we’ll work on once we’ve shipped WebRender to our entire user population. There’s lots to do! An overall theme is currently emerging in our planning – Visual Quality and Performance! We’re investigating various opportunities to extend the WebRender pipeline deeper into Gecko’s layout engine, HDR features, improved color management, performance improvements for SVG and Canvas, and improvements in power consumption. We’ll post more about these projects in future posts, stay tuned!
Happy New Year from the Mozilla Graphics Team!
Bonjour à tous et à toutes, this is episode 53 of your favorite and only Firefox graphics newsletter. From now on instead of peeling through commit logs, I will be simply gathering notes sent to me by the rest of the team. This means the newsletter will be shorter, hopefully a bit less overwhelming with only the juicier bits. It will also give yours-truly more time to fix bugs instead of writing about it.
Lately we have been enabling WebRender for a lot more users. For the first time, WebRender is enabled by default in Nightly for Windows 7 and macOS users with modern GPUs. Today 78% of Nightly users have WebRender enabled, 40% on beta, and 22% on release. Not all of these configurations are ready to ride the trains yet, but the numbers are going to keep going up over the next few releases.
WebRender WebRender is a GPU based 2D rendering engine for the web written in Rust, currently powering Firefox‘s rendering engine as well as Mozilla’s research web browser Servo.
Ongoing work * Part of the team is now focusing on shipping WebRender on some flavors of Linux as well. * Worth highlighting also is the ongoing work by Martin Stránský and Robert Mader to switch Firefox on Linux from GLX to EGL. EGL is a more modern and better supported API, it will also let us share more code between Linux and Android. * Lee and Jim continue work on WebRender’s software backend. It has had a bunch of correctness improvements, works properly on Windows now and has more performance improvements in the pipeline. It works on all desktop platforms and can be enabled via the pref “gfx.webrender.software”.
Performance One of the projects that we worked on the last little while has been improving performance on lower-end/older Intel GPUs.
Some other performance improvements that we made are:
Driver bugs * Dzmitry worked around a driver bug causing visual artifacts in Firefox’s toolbar on Intel Skylake and re-enabled direct composition on these configurations.
Desktop zooming
* Botond announced on dev-platform that desktop zooming is ready for dogfooding by Nightly users who would like to try it out by flipping the pref.
* Botond landed a series of patches that re-works how main-thread hit testing accounts for differences between the visual and layout viewports. This fixes a number of scenarios involving the experimental desktop zooming feature (enabled using apz.allow_zooming=true), including allowing scrollbars to be dragged with desktop zooming enabled.
* Timothy landed support for DirectManipulation preffed off. It allows users to pinch-zoom on touchpads on Windows. It can be enabled by setting apz.windows.use_direct_manipulation=true
Bonjour à tous et à toutes, this is episode 53 of your favorite and only Firefox graphics newsletter. From now on instead of peeling through commit logs, I will be simply gathering notes sent to me by the rest of the team. This means the newsletter will be shorter, hopefully a bit less overwhelming with … Continue reading moz://gfx newsletter #53 →
Hello everyone! I know you have been missing your favorite and only newsletter about software engineers staying at home, washing their hands often and fixing strange rendering glitches in Firefox’s graphics engine. In the last two months there has been a heap of fixes and improvements. Before the usual change list I’ll go through a few highlights:
SWGL (pronounced “swigle”), which will in the long run let us move even the most exotic hardware configurations to WebRender.What’s new in gfx * Botond and Micah Tigley added initial support for double-click-to-zoom gestures in Responsive Design Mode * Botond and Agi Sferro tracked down and fixed a regression that was causing about:support to load zoomed in on Android. * Sotaro re-enabled video frame recycling with the RDD process. * Sotaro fixed an issue canvases to not be re-created after GPU context loss. * Lee worked around a memory leak. * Markus fixed a rendering glitch. * Jonathan Kew avoided defaulting to a monospace font as fallback on MacOS. * Nical attempted yet another fix at a crash that keeps coming back. * Jonathan Kew implemented distinguishing between OS-provided and user-installed fonts in the system font list. * Botond fixed non-unified build errors. * Kats improved the behavior of momentum scrolling. * Jonathan Kew fixed a crash. * Kats prevented the viewport clip from clipping position:sticky items. * Kris added desktop-zooming information to about:support. * Snorp made it possible to disambiguate top-level from other APZ events. * Roger Zanoni addressed some static analysis lints. * Chris Martin removed some usage of gdi surfaces on windows for sandboxing. * Andrew enabled color management for all images and not only tagged ones. * Jushua Gahan addressed some static analysis lints. * Timothy fixed an invalidation issue with display:none masks. * Sotaro fixed a canvas rendering issue when resuming on Android. * Jonathan Kew fixed a font metrics related issue. * Bob Owen fixed an intermittent issue with canvas remoting. * Kats fixed some issues with the dynamic toolbar sticky behavior on Android. * Miko fixed an issue with opacity optimization. * Bert improved the vsync implementation on Windows. * Arash Fotouhi addressed some static analysis lints. * Robert Mader implemented creating an OpenGL context with the Wayland backend on Linux. * Lee fixed a shutdown crash related to font loading. * Jonathan Kew fixed a printing issue with long SVG stroke-dasharray strings. * Sam Dalton improved the FPS counter implementation. * Kats removed the old android dynamic toolbar implementation. * Sotaro improved some OpenGL context debugging utilities. * Jonathan Kew fixed a font visibility issue with language-pack fonts on Windows.
What’s new in WebRender WebRender is a GPU based 2D rendering engine for the web written in Rust, currently powering Firefox‘s rendering engine as well as Mozilla’s research web browser Servo.
To enable WebRender in Firefox, in the about:config page, enable the pref gfx.webrender.all and restart the browser.
WebRender is available under the MPLv2 license as a standalone crate on crates.io (documentation) for use in your own rust projects.
What’s new in WebGPU WebGPU is a new Web API to access graphics and compute capabilities of the hardware. Firefox and Servo have implementations in progress that are based on wgpu project written in Rust.
To enable WebGPU, follow the steps in webgpu.io, which also shows the current implementation status in all browsers.
Hello everyone! I know you have been missing your favorite and only newsletter about software engineers staying at home, washing their hands often and fixing strange rendering glitches in Firefox’s graphics engine. In the last two months there has been a heap of fixes and improvements. Before the usual change list I’ll go through a … Continue reading moz://gfx newsletter #52 →
Bonjour, bonjour! Another long overdue episode of your favourite Mozilla gfx team newsletter is here. A few weeks ago, Jessie published a call to help us find steps to reproduce a mysterious glitch. Thanks a ton to everyone who helped out with this one! Glenn landed a fix to an issue that we suspect might be the cause of the issues . Don’t hesitate to let us know if you are still running into this particular glitch with Firefox Nightly and WebRender enabled.
Other than that there are a number of pretty exciting things going on in WebRender. One of them is Lee and Jeff’s work on a software backend for WebRender. In order to eventually move all Firefox users to WebRender, we need a backend that can accomodate for very old GPUs and very buggy drivers. Ideally this backend would use most of WebRender’s current code and infrastructure to avoid having too much new code (and bugs!) to maintain with our limited resources. One of the avenues that was investigated is using a software emulation layer for OpenGL such as Swift Shader or llvm-pipe as a black box to run our GPU code on the CPU. We unfortunately couldn’t get good enough performance this way so Lee is now experimenting with automatically translating our shaders into SIMD-optimized CPU code while compiling Firefox instead, with SIMD optimizations. These “software shaders” are then run into a simple custom rasterizer that only supports the few OpenGL features that we need and take advantage of the restricted featureset to run as fast as possible. This is still very much experimental but initial results are promising.
A lot of progress was also made towards DirectCompositor integration which I have mentioned a few times in this blog. Glenn, Sotaro and Jeff are ironing out the last few bugs (famous last words!) before the feature can ride the trains to release. A lot of work went into making video playback very efficient in this new compositing mode.
What’s new in gfx * Botond and Ting-Yu collaborated to fix an Android regression where pinch-zooming while text is selected could cause the view to jump to the top-left corner of the page. * Kats fixed a task exhaustion issue with the hit-testing dumping code. * Botond and Decoder fixed a race condition; * Botond fixed some race conditions in APZ caught by thread sanitizer. * Kats reenabled test_group_pointerevents.html for GeckoView. * Martin Stránský avoided passing invalid file descriptors through IPC with dmabuf textures on Wayland. * Bob Owen fixed a crash with canvas remoting. * Kris fixed a crash. * Martin Stránský made the GL compositor backend work with NV12 video textures produced by ffmpeg on Wayland. * Martin Stránský added support for wayland dmabuf textures with WebGL. * Martin Stránský implemented fence synchronization to dmabuf surfaces for WebGL on Wayland. * Sotaro prevented the creation of unnecessary compositor windows. * Sotaro improved the shutdown logic of the VR code. * Markus fixed an invalidation bug with CoreAnimation. * Botond fixed an issue with window.scrollY after maximizing the window. * Martin Stránský implemented dmabuf modifiers. * Tim Nguyen implemented conic gradients with the skia backend. * Nical fixed a crash in the D2D backend. * Jeff Gilbert fixed WebGLSL comment parsing. * Jeff Gilbert optimized GetDrawFetchLimits and vertexAttribPointer in WebGL. * Imanol Fernandez fixed a WebGL crash affecting Firefox reality. * Jeff Gilbert fixed failures in the CTS/conformance2/extensions test suite. * Boris Zbarsky made canvas error handling better match the specification when creating a pattern from an invalid image. * Jeff Gilbert fixed an issue with canvas drawImage and non-premultiplied source images. * Jeff Gilbert improved the performance of the VAO cache under in some cases.
What’s new in WebRender WebRender is a GPU based 2D rendering engine for the web written in Rust, currently powering Firefox‘s rendering engine as well as Mozilla’s research web browser Servo.
To enable WebRender in Firefox, in the about:config page, enable the pref gfx.webrender.all and restart the browser.
WebRender is available under the MPLv2 license as a standalone crate on crates.io (documentation) for use in your own rust projects.
What’s new in WebGPU Kvark implemented resource binding, compute pass recording, and reworked the asynchronous buffer mapping. All of that has landed now, and Firefox Nightly is able to run the standard compute example :tada: (when the pref is enabled)
Kvark spoke at Fosdem 2020 about our Rust-based WebGPU infrastructure. This presentation was derived from an internal talk about WebGPU that happened at Berlin All Hands, slides from which are also available. It had more focus on the Web API and Firefox architecture.
Bonjour, bonjour! Another long overdue episode of your favourite Mozilla gfx team newsletter is here. A few weeks ago, Jessie published a call to help us find steps to reproduce a mysterious glitch. Thanks a ton to everyone who helped out with this one! Glenn landed a fix to an issue that we suspect might … Continue reading moz://gfx newsletter #51 →
For the past little while, we have been tracking some interesting WebRender bugs that people are reporting in release. Despite best efforts, we have been unable to determine clear steps to reproduce these issues and have been unable to find a fix for them. Today we are announcing a special challenge to the community – help us track down steps to reproduce (a.k.a STR) for this bug and you will win some special, limited edition Firefox Graphics team swag! Read on for more details if you are interested in participating.
What we know so far about the bug: Late last year we started seeing reports of random UI glitching bugs that people were seeing in release. You can check out some of the reports on Bugzilla. Here is what we know so far about this bug:
Glitches! Black boxes! * The majority of the reports we have seen so far have come from people using NVIDIA graphics cards, although we have seen reports come in of this happening on Intel and AMD as well. That could be though because the majority of the people we have officially shipped WR to in release are on NVIDIA cards. * There doesn’t seem to be one clear driver version correlated to this bug, so we are not sure if it is a driver bug. * All reporters so far have been using Windows 10 * No one who has reported the bug thus far has been able to determine clear and consistent STR, and no one on the Graphics team has found a way to reproduce it either. We all use WebRender daily and none of us have encountered the bug.
How can you help? Without having a way to reliably reproduce this bug, we are at a loss on how to solve it. So we decided to hold a challenge to engage the community further to help us understand this bug better. If you are interested in helping us get to the root of this tricky bug, please do the following:
Even if you can’t easily find STR, we are still interested in hearing about whether you see this bug!
Challenge guidelines The winners of this challenge will be chosen based on the following criteria:
Update: we have created the channel #gfx-wr-glitch:mozilla.org on Matrix so you can ask questions/chat with us there. For more info about how to joing Matrix, check out: https://wiki.mozilla.org/Matrix
For the past little while, we have been tracking some interesting WebRender bugs that people are reporting in release. Despite best efforts, we have been unable to determine clear steps to reproduce these issues and have been unable to find a fix for them. Today we are announcing a special challenge to the community – … Continue reading Challenge: Snitch on the glitch! Help the Graphics team track down an interesting WebRender bug… →
Hi there! Another gfx newsletter incoming.
Glenn and Sotaro’s work on integrating WebRender with DirectComposition on Windows is close to being ready. We hope to let it ride the trains for Firefox 75. This will lead to lower GPU usage and energy consumption. Once this is done we plan to follow up with enabling WebRender by default for Windows users with (some subset of) Intel integrated GPUs, which is both challenging (these integrated GPUs are usually slower than discrete GPUs and we have run into a number of driver bugs with them on Windows) and rewarding as it represents a very large part of the user base.
Edit: Thanks to Robert in the comments section of this post for mentioning the Linux/Wayland progress! I copy-pasted it here:
Some additional highlights for the Linux folks: Martin Stránský is making good progress on the Wayland front, especially concerning DMABUF. It will allow better performance for WebGL and hardware decoding for video (eventually). Quoting from https://bugzilla.mozilla.org/show_bug.cgi?id=1586696#c2:
there’s a WIP dmabuf backend patch for WebGL, I see 100% performance boost with it for simple WebGL samples at GL compositor (it’s even faster than chrome/chromium on my box).
And there is active work on partial damage to reduce power consumption: https://bugzilla.mozilla.org/show_bug.cgi?id=1484812
What’s new in gfx
* Handyman fixed fixed a crash in the async plugin infrastructure.
* Botond fixed (2) various data races in the APZ code.
* Sean Feng fixed another race condition in APZ code.
* Andrew fixed a crash with OMTP and image decoding.
* Sotaro fixed a crash with the GL compositor on Wayland.
* Botond worked with Facebook developers to resolve a scrolling-related usability problem affecting Firefox users on messenger.com, primarily on MacOS.
* Botond fixed (2) divisions by zero various parts of the APZ.
* Sean Feng added some telemetry for touch input latency.
* Timothy made sure all uses of APZCTreeManager::mGeckoFixedLayerMargins are protected by the proper mutex.
* Boris Chiou moved animations of transforms with preserve-3d off the main thread
* Jamie clamped some scale transforms at 32k to avoid excessively large rasterized areas.
* Jonathan Kew reduced the emboldening strength used for synthetic-bold faces with FreeType.
* Andrew implemented NEON accelerated methods for unpacking RGB to RGBA/BGRA.
* Alex Henrie fixed a bug in Moz2D’s Skia backend.
What’s new in WebRender WebRender is a GPU based 2D rendering engine for the web written in Rust, currently powering Firefox‘s rendering engine as well as Mozilla’s research web browser servo.
setVerticalClipping API for WebRender.To enable WebRender in Firefox, in the about:config page, enable the pref gfx.webrender.all and restart the browser.
WebRender is available under the MPLv2 license as a standalone crate on crates.io (documentation) for use in your own rust projects.
What’s new in Wgpu * Kvark implemented buffer creation and mapping, with an ability to both provide data and read it back from the GPU. * Kvark set up the synchronization from Mozilla Central to Github repository. * jdashg created a separate category for WebGPU mochitests. * Kvark heavily reworked lifetime and usage tracking of resources. * Many fixes and improvements were made by the contributors to wgpu (thank you!)
Hi there! Another gfx newsletter incoming. Glenn and Sotaro’s work on integrating WebRender with DirectComposition on Windows is close to being ready. We hope to let it ride the trains for Firefox 75. This will lead to lower GPU usage and energy consumption. Once this is done we plan to follow up with enabling WebRender … Continue reading moz://gfx newsletter #50 →
By way of introduction, I invite you to read Markus’ excellent post on this blog about CoreAnimation integration yielding substantial improvements in power usage if you haven’t already.
Next steps in this OS compositor integration saga include taking advantage CoreAnimation with WebRender’s picture caching infrastructure (rendering tiles directly into CoreAnimation surfaces), as well as rendering using a similar mechanism on Windows via DirectComposition surfaces. Markus, Glenn and Sotaro are making good progress on all of these fronts.
What’s new in gfx
WebGPU
Kvark landed WebGPU’s infrastructure and initial implementation on Nightly. It can be enabled via the pref “dom.webgpu.enable” in about:config. The functionality is limited to device creation at the moment, with support for Vulkan, D3D12, and Metal.
WebGPU Is a work-in-progress specification for the successor to WebGL 2, exposing a modern API to perform rendering and computation on the GPU.
Various bug fixes and improvements * Botond fixed a bug that caused WebExtension popups to render empty with desktop zooming. * Botond fixed a WebRender scrolling regression that affected some workflows in Tile Tabs and similar extensions. * Botond fixed some Android UX issues related to gesture handling (bug 1570559, bug 1586496). * Botond fixed some Android scrolling webcompat issues (bug 1592435, bug 1592902). * Botond fixed some more prerequisites for enabling a hiding URL bar in Firefox Preview (bug 1552608, bug 1590582). * Markus shared the GL contexts between open windows on Mac. * Bob Owen improved the recycling of shared textures. * Jonathan Kew fixed a sub-pixel anti-aliasing issue when the text color has some transparency and an emoji is present. * Sotaro fixed an issue with DWM, partial present and high-contrast mode on Windows. * Andrew allowed image decoders to choose RGBA and BGRA at compile time. * Nical Fixed a shutdown crash. * Sotaro fixed an issue with partial present and the snapshot mechanism used for reftests. * Jonathan Kew enabled a better default fallback font for Mongolian on macOS. * Jonathan fixed a whole lot of other font rendering issues. * Lee updated Skia to version m79. * Jamie avoided using glTexImage3D on android emulator.
What’s new in WebRender WebRender is a GPU based 2D rendering engine for web written in Rust, currently powering Firefox‘s rendering engine as well as the research web browser servo.
To enable WebRender in Firefox, in the about:config, enable the pref gfx.webrender.all and restart the browser.
WebRender is available as a standalone crate on crates.io (documentation) for use in your own rust projects.
By way of introduction, I invite you to read Markus’ excellent post on this blog about CoreAnimation integration yielding substantial improvements in power usage if you haven’t already. Next steps in this OS compositor integration saga include taking advantage CoreAnimation with WebRender’s picture caching infrastructure (rendering tiles directly into CoreAnimation surfaces), as well as rendering … Continue reading moz://gfx newsletter #49 →