The Complete Internet At Most FPS: How WebRender Removes Jank

By | October 10, 2017

The Firefox Quantum launch is getting shut. It brings many efficiency enhancements, together with the super quick CSS engine that we introduced over from Servo.

But theres one other massive piece of Servo know-how thats not in Firefox Quantum fairly but, although its coming quickly. Thats WebRender, which is being added to Firefox as half of the Quantum Render project.Drawing of a jet engine labeled with different Mission Quantum projects

WebRender is understood for being extraordinarily quick. However WebRender isnt actually about making rendering sooner. Its about making it smoother.

With WebRender, we wish apps to run at a silky easy 60 frames per second (FPS) or higher irrespective of how massive the show is or how a lot of the web page is altering from body to border. And it actually works. Pages that chug alongside at 15 FPS in Chrome or todays Firefox run at 60 FPS with WebRender.

So how does WebRender do that? It basically modifications the greatest way the rendering engine works to make it extra like a 3D sport engine.

Lets check out what this implies. However first

What does a renderer do?

In the article on Stylo, I talked about how the browser goes from HTML and CSS to pixels on the display screen, and the way most browsers do that in 5 steps.

We can cut up these 5 steps into two halves. The primary half mainly builds up a plan. To make this plan, it combines the HTML and CSS with info just like the viewport measurement to determine precisely what each ingredient ought to look likeits width, peak, colour, and many others. The tip result’s one thing referred to as a body tree or a render tree.

The second halfpainting and compositingis what a renderer does. It takes that plan and turns it into pixels to show on the screen.

Diagram dividing the 5 phases of rendering into two teams, with a body tree being handed from half 1 to half 2

But the browser doesnt simply have to do that as quickly as for an online web page. It has to do it over and over for a similar net web page. Any time one thing modifications on this pagefor instance, a div is toggled openthe browser has to undergo loads of these steps.

Diagram exhibiting the steps that get redone on a click on: type, format, paint, and composite

Even in circumstances the place nothings actually altering on the pagefor instance the place youre scrolling or the place you’re highlighting some textual content on the pagethe browser nonetheless has to undergo at the very least among the second half once more to attract new pixels on the screen.

Diagram exhibiting the steps that get redone on scroll: composite

If you need issues like scrolling or animation to look easy, they must be going at 60 frames per second.

You can have heard this phraseframes per second (FPS)earlier than, with out being certain what it meant. I consider this like a flip guide. Its like a guide of drawings which are static, however you need to use your thumb to flip by in order that it seems just like the pages are animated.

In order for the animation on this flip guide to look easy, you’ll need to have 60 pages for each second within the animation.

Picture of a flipbook with a easy animation subsequent to it

The pages on this flip guide are made out of graph paper. There are tons and many little squares, and every of the squares can solely include one color.

The job of the renderer is to fill within the bins on this graph paper. As quickly as all the bins within the graph paper are stuffed in, it’s completed rendering the frame.

Now, after all there’s not precise graph paper inside your pc. As a substitute, theres a bit of reminiscence within the pc referred to as a body buffer. Every reminiscence deal with within the body buffer is form of a field within the graph paper it corresponds to a pixel on the display screen. The browser will fill in each slot with the numbers that characterize the colour in RGBA (red, inexperienced, blue, and alpha) values.

A stack of reminiscence addresses with RGBA values which are correlated to squares in a grid (pixels)

When the show must refresh itself, it will take a glance at this part of memory.

Most pc shows will refresh 60 instances per second. Because of this browsers attempt to render pages at 60 frames per second. Meaning the browser has 16.67 milliseconds to do all the setup CSS styling, format, paintingand fill in all the slots within the body buffer with pixel colours. This time-frame between two frames (16.67 ms) known as the body budget.

Sometimes you hear individuals discuss dropped frames. A dropped body is when the system doesnt end its work inside the body funds. The show tries to get the model new body from the body buffer earlier than the browser is completed filling it in. On this case, the show exhibits the outdated model of the body again.

A dropped body is form of like should you tore a web page out of that flip guide. It will make the animation appear to stutter or soar as a end result of youre lacking the transition between the earlier web page and the next.

Picture of a flipbook lacking a web page with a janky animation subsequent to it

So we need to ensure that we get all of those pixels into the body buffer earlier than the show checks it once more. Lets take a glance at how browsers have traditionally performed this, and the way that has modified over time. Then we will see how we will make this faster.

A temporary historical past of portray and compositing

Note: Portray and compositing is the place browser rendering engines are essentially the most different from one another. Single-platform browsers (Edge and Safari) work a bit in one other way than multi-platform browsers (Firefox and Chrome) do.

Even within the earliest browsers, there have been some optimizations to make pages render sooner. For instance, should you have been scrolling content material, the browser would keep the half that was nonetheless seen and transfer it. Then it will paint new pixels within the clean spot.

This technique of determining what has modified after which solely updating the modified components or pixels known as invalidation

As time went on, browsers began making use of extra invalidation strategies, like rectangle invalidation. With rectangle invalidation, you determine the smallest rectangle round each half of the display screen that modified. Then, you solely redraw whats inside these rectangles.

This actually reduces the quantity of labor that you’ll need to do when theres not a lot altering on the web page for instance, when you might have a single blinking cursor.

Blinking cursor with small repaint rectangle round it

But that doesnt help a lot when massive components of the web page are altering. So the browsers got here up with new strategies to deal with these cases.

Introducing layers and compositing

Using layers might help rather a lot when massive components of the web page are altering at the very least, in certain cases.

The layers in browsers are rather a lot like layers in Photoshop, or the onion pores and skin layers that have been utilized in hand-drawn animation. Mainly, you paint different components of the web page on different layers. Then you definitely then place these layers on prime of every other.

They have been part of the browser for a really lengthy time, however they werent all the time used to hurry issues up. At first, they have been simply used to ensure pages rendered accurately. They corresponded to one thing referred to as stacking contexts.

For instance, should you had a translucent ingredient, it will be in its personal stacking context. That meant it received its personal layer so you might possibly mix its colour with the colour beneath it. These layers have been thrown out as quickly because the body was performed. On the subsequent body, all the layers can be repainted again.

Layers for opacity generated, then body rendered, then thrown out

But often the issues on these layers didnt change from body to border. For instance, consider a conventional animation. The background doesnt change, even when the characters within the foreground do. Its much more environment friendly to maintain that background layer round and simply reuse it.

So thats what browsers did. They retained the layers. Then the browser might simply repaint layers that had modified. And in some circumstances, layers werent even altering. They only wanted to be rearrangedfor instance, if an animation was shifting throughout the display screen, or one thing was being scrolled.

Two layers shifting relative to one another as a scroll field is scrolled

This technique of arranging layers collectively known as compositing. The compositor begins with:

source bitmaps: the background (including a clean field the place the scrollable content material ought to be) and the scrollable content material itselfa vacation spot bitmap, which is what will get displayed on the screen

First, the compositor would copy the background to the vacation spot bitmap.

Then it will work out what half of the scrollable content material ought to be exhibiting. It will copy that half over to the vacation spot bitmap.

Source bitmaps on the left, vacation spot bitmap on the right

This diminished the quantity of portray that the primary thread needed to do. But it surely nonetheless implies that the primary thread is spending loads of time on compositing. And there are many issues competing for time on the primary thread.

Ive talked about this earlier than, however the primary thread is form of like a full-stack developer. Its answerable for the DOM, format, and JavaScript. And it additionally was answerable for portray and compositing.

Main thread doing DOM, JS, and format, plus paint and composite

Every millisecond the primary thread spends doing paint and composite is time it cant spend on JavaScript or layout.

CPU engaged on portray and considering "I actually ought to get to that JS soon"

But there was one other half of the hardware that was mendacity round with out a lot work to do. And this hardware was particularly constructed for graphics. That was the GPU, which video games have been utilizing because the late 90s to render frames shortly. And GPUs have been getting greater and extra highly effective ever since then.

A drawing of a pc chip with four CPU cores and a GPU

GPU accelerated compositing

So browser builders began shifting issues over to the GPU.

There are two duties that might probably transfer over to the GPU:

Painting the layersCompositing them together

It could be arduous to maneuver portray to the GPU. So for essentially the most half, multi-platform browsers saved portray on the CPU.

But compositing was one thing that the GPU might do in a quick time, and it was easy to maneuver over to the GPU.

Main thread passing layers to GPU

Some browsers took this parallelism even additional and added a compositor thread on the CPU. It grew to become a supervisor for the compositing work that was occurring on the GPU. This meant that if the primary thread was doing one thing (like working JavaScript), the compositor thread might nonetheless deal with issues for the person, like scrolling content material up when the person scrolled.

Compositor thread sitting between primary thread and GPU, passing layers to GPU

So this strikes all the compositing work off of the primary thread. It nonetheless leaves loads of work on the primary thread, although. Every time we have to repaint a layer, the primary thread must do it, after which switch that layer over to the GPU.

Some browsers moved portray off to a different thread (and have been engaged on that in Firefox today). However its even sooner to maneuver this last little little bit of work??painting??to the GPU.

GPU accelerated painting

So browsers began shifting portray to the GPU, too.

Paint and composite dealt with by the GPU

Browsers are nonetheless within the course of of creating this shift. Some browsers paint on the GPU all the time, whereas others solely do it on certain platforms (like solely on Home windows, or solely on cell devices).

Painting on the GPU does a few issues. It frees up the CPU to spend all of its time doing issues like JavaScript and format. Plus, GPUs are a lot sooner at drawing pixels than CPUs are, so it speeds portray up. It additionally means much less knowledge must be copied from the CPU to the GPU.

But sustaining this division between paint and composite nonetheless has some prices, even when they’re each on the GPU. This division additionally limits the sorts of optimizations that you need to use to make the GPU do its work faster.

This is the place WebRender is accessible in. It basically modifications the greatest way we render, eradicating the excellence between paint and composite. This provides us a strategy to tailor the efficiency of our renderer to provide the greatest person expertise on todays net, and to greatest help the use circumstances that you will note on tomorrows web.

This means we dont simply need to make frames render sooner we need to make them render extra constantly and with out jank. And even when there are many pixels to attract, like on 4k shows or WebVR headsets, we nonetheless need the expertise to be simply as smooth.

When do present browsers get janky?

The optimizations above have helped pages render sooner in certain circumstances. When not a lot is altering on a pagefor instance, when theres only a single blinking cursorthe browser will do the least quantity of labor possible.

Blinking cursor with small repaint rectangle round it

Breaking up pages into layers has expanded the variety of these best-case eventualities. Should you can paint a few layers after which simply transfer them round relative to one another, then the painting+compositing structure works well.

Rotating clock hand as a layer on prime of one other layer

But there are additionally commerce offs to utilizing layers. They take up loads of reminiscence and may truly make issues slower. Browsers need to mix layers the place it is smart however its arduous to inform the place it makes sense.

This implies that if there are loads of various things shifting on the web page, you’ll have the ability to find yourself with too many layers. These layers replenish reminiscence and take too lengthy to switch to the compositor.

Many layers on prime of every other

Other instances, youll find yourself with one layer when you must have a quantity of layers. That single layer shall be regularly repainted and transferred to the compositor, which then composites it with out altering anything.

This means youve doubled the quantity of drawing you must do, touching each pixel twice with out getting any profit. It will have been sooner to easily render the web page straight, with out the compositing step.

Paint and composite producing the identical bitmap

And there are many circumstances the place layers simply dont help a lot. For instance, should you animate background colour, the entire layer must be repainted anyway. These layers solely help with a small variety of CSS properties.

Even if most of your frames are best-case scenariosthat is, they solely take up a tiny little bit of the body budgetyou can nonetheless get uneven movement. For perceptible jank, solely a few frames need to fall into worst-case scenarios.

Frame timeline with a few frames that go over the body funds, inflicting jank

These eventualities are referred to as efficiency cliffs. Your app appears to be shifting alongside fantastic till it hits one in all these worst-case eventualities (like animating background color) and all the sudden your apps body fee topples over the edge.

Person falling over the sting of a cliff labeled animating background color

But we will eliminate these efficiency cliffs.

How can we do that? We comply with the lead of 3D sport engines.

Using the GPU like a sport engine

What if we stopped attempting to guess what layers we’d like? What if we eliminated this boundary between portray and compositing and simply went again to portray each pixel on each frame?

This may sound like a ridiculous thought, but it surely truly has some precedent. Modern-day video video games repaint each pixel, they usually keep 60 frames per second extra reliably than browsers do. They usually do it in an surprising approach as a substitute of creating these invalidation rectangles and layers to reduce what they should paint, they only repaint the entire screen.

Wouldnt rendering an online web page like that be approach slower?

If we paint on the CPU, it will be. However GPUs are designed to make this work.

GPUs are constructed for excessive parallelism. I talked about parallelism in my last article about Stylo. With parallelism, the machine can do a quantity of issues on the identical time. The variety of issues it might possibly do directly is restricted by the variety of cores that it has.

CPUs often have between 2 and eight cores. GPUs often have at the very least a few hundred cores, and infrequently greater than 1,000 cores.

These cores work a bit of in one other way, although. They cant act fully independently like CPU cores can. As a substitute, they often work on one thing collectively, working the identical instruction on different items of the data.

CPU cores working independently, GPU cores working together

This is precisely what you wish when youre filling in pixels. Every pixel could be stuffed in by a distinct core. As a end result of it might possibly work on a complete lot of pixels at a time, the GPU is rather a lot sooner at filling in pixels than the CPU however provided that you make certain that all of these cores have work to do.

Because cores need to work on the identical factor on the identical time, GPUs have a reasonably inflexible set of steps that they undergo, and their APIs are fairly constrained. Lets check out how this works.

First, you’ll need to inform the GPU what to attract. This implies giving it shapes and telling it easy strategies to fill them in.

To do that, you break up your drawing into easy shapes (usually triangles). These shapes are in 3D area, so some shapes could be behind others. Then you definitely take all the corners of these triangles and put their x, y, and z coordinates into an array.

Then you concern a draw callyou inform the GPU to attract these shapes.

CPU passing triangle coordinates to GPU

From there, the GPU takes over. All the cores will work on the identical factor on the identical time. They will:

Figure out the place all the corners of the shapes are. That is referred to as vertex shading.

GPU cores drawing vertexes on a graph

Figure out the traces that join these corners. From this, you’ll have the ability to work out which pixels are coated by the form. Thats referred to as rasterization.

GPU cores drawing traces between vertexes

Now that we all know what pixels are coated by a form, undergo each pixel within the form and work out what colour it ought to be. That is referred to as pixel shading.

GPU cores filling in pixels

This last step could be performed in numerous methods. To inform the GPU easy strategies to do it, you give the GPU a program referred to as a pixel shader. Pixel shading is amongst the few components of the GPU which you can program.

Some pixel shaders are easy. For instance, in case your form is a single colour, then your shader program simply must return that colour for each pixel within the shape.

Other instances, its extra advanced, like when you might have a background picture. You’ll need to work out which half of the picture corresponds to every pixel. You are capable of do this in the identical approach an artist scales a picture up or down put a grid on prime of the picture that corresponds to every pixel. Then, as quickly as you recognize which field corresponds to the pixel, take samples of the colours inside that field and work out what the colour ought to be. That is referred to as texture mapping as a end result of it maps the picture (called a texture) to the pixels.

Hi-res picture being mapped to a a lot decrease decision space

The GPU will name your pixel shader program on each pixel. Totally different cores will work on different pixels on the identical time, in parallel, however all of them must be utilizing the identical pixel shader program. While you inform the GPU to attract your shapes, you inform it which pixel shader to use.

For nearly any net web page, different components of the web page might need to use different pixel shaders.

Because the shader applies to all the shapes within the draw name, you often have to interrupt up your draw calls in a quantity of teams. These are referred to as batches. To maintain all the cores as busy as potential, you need to create a small variety of batches which have plenty of shapes in them.

CPU passing a field containing plenty of coordinates and a pixel shader to the GPU

So thats how the GPU splits up work throughout a complete lot or 1000’s of cores. Its solely due to this excessive parallelism that we will consider rendering every thing on each body. Even with the intense parallelism, although, its nonetheless loads of work. You proceed to must be good about the way you do that. Heres the place WebRender comes in

How WebRender works with the GPU

Lets return to take a glance at the steps the browser goes by to render the web page. Two issues will change here.

Diagram exhibiting the phases of the rendering pipeline with two modifications. The body tree is now a show record an paint and composite have been mixed into Render.

Theres now not a distinction between paint and composite they’re each half of the identical step. The GPU does them on the identical time based mostly on the graphics API instructions that have been handed to it.Layout now provides us a distinct knowledge construction to render. Earlier than, it was one thing referred to as a body tree (or render tree in Chrome). Now, it passes off a show list.

The show record is a set of high-level drawing directions. It tells us what we have to draw with out being particular to any graphics API.

Whenever theres one thing new to attract, the primary thread provides that show record to the RenderBackend, which is WebRender code that runs on the CPU.

The RenderBackends job is to take this record of high-level drawing directions and convert it to the draw calls that the GPU wants, which are batched collectively to make them run faster.

Diagram of the four different threads, with a RenderBackend thread between the primary thread and compositor thread. The RenderBackend thread interprets the show record into batched draw calls

Then the RenderBackend will cross these batches off to the compositor thread, which passes them to the GPU.

The RenderBackend needs to make the draw calls its giving to the GPU as quick to run as potential. It makes use of a few different strategies for this.

Removing any pointless shapes from the record (Early culling)

The greatest strategy to save time is to not do the work at all.

First, the RenderBackend cuts down the record of show objects. It figures out which show items will truly be on the display screen. To do that, it seems at issues like how far down the scroll is for each scroll box.

If any half of a form is inside the field, then it’s included. If not one in all the form would have proven up on the web page, although, its eliminated. This course of known as early culling.

A browser window with some components off display screen. Subsequent to that could additionally be a show record with the offscreen components removed

Minimizing the variety of intermediate textures (The render job tree)

Now we’ve got a tree that solely accommodates the shapes nicely use. This tree is organized into these stacking contexts we talked about before.

Effects like CSS filters and stacking contexts make issues a bit of sophisticated. For instance, let’s imagine you might have a component that has an opacity of 0.5 and it has kids. You may suppose that every youngster is clear however its truly the entire group thats transparent.

Three overlapping bins which are translucent, so that they show by one another, subsequent to a translucent form fashioned by the three bins the place the bins do not show by each other

Because of this, you’ll need to render the group out to a texture first, with each field at full opacity. Then, when youre inserting it within the mum or dad, you’ll have the ability to change the opacity of the entire texture.

These stacking contexts could be nested that mum or dad is perhaps half of one other stacking context. Which suggests it must be rendered out to a different intermediate texture, and so on.

Creating the area for these textures is pricey. As a lot as potential, we need to group issues into the identical intermediate texture.

To help the GPU do that, we create a render job tree. With it, we all know which textures must be created earlier than different textures. Any textures that dont rely upon others could be created within the first cross, which suggests they are often grouped collectively in the identical intermediate texture.

So within the instance above, wed first do a cross to output one nook of a field shadow. (Its barely extra sophisticated than this, however that is the gist.)

A 3-level tree with a root, then an opacity youngster, which has three field shadow kids. Subsequent to that could additionally be a render goal with a field shadow corner

In the second cross, we will mirror this nook throughout the field to put the field shadow on the bins. Then we will render out the group at full opacity.

Same 3-level tree with a render goal with the three field form at full opacity

Next, all we have to do is change the opacity of this texture and place it the place it must go within the last texture that shall be output to the screen.

Same tree with the vacation spot goal exhibiting the three field form at decreased opacity

By build up this render job tree, we work out the minimal variety of offscreen render targets we will use. Thats good, as a end result of as I discussed, creating the area for these render goal textures is expensive.

It additionally helps us batch issues together.

Grouping draw calls collectively (Batching)

As we talked about earlier than, we have to create a small variety of batches which have plenty of shapes in them.

Paying consideration to the way you create batches can actually pace issues up. You need to have as many shapes in the identical batch as you’ll have the ability to. That is for a few reasons.

First, every time the CPU tells the GPU to do a draw name, the CPU has to do loads of work. It has to do issues like arrange the GPU, add the shader program, and check for various hardware bugs. This work provides up, and whereas the CPU is doing this work, the GPU is perhaps idle.

Second, theres a price to altering state. Let’s imagine that you’ll need to change the shader program between batches. On a typical GPU, you’ll need to wait till all the cores are performed with the present shader. That is referred to as draining the pipeline. Till the pipeline is drained, different cores shall be sitting idle.

Mulitple GPU cores standing round whereas one finishes with the earlier pixel shader

Because of this, you need to batch as a lot as potential. For a typical desktop PC, you need to have a hundred draw calls or fewer per body, and also you need each name to have 1000’s of vertices. That approach, youre making one of the best use of the parallelism.

We take a glance at each cross from the render job tree and work out what we will batch together.

At the second, each of different sorts of primitives requires a distinct shader. For instance, theres a border shader, and a textual content shader, and a picture shader.

Boxes labeled with the variety of batch they include (e.g. Borders, Photos, Rectangles)

We imagine we will mix loads of these shaders, which is in a position to permit us to have even greater batches, however that is already fairly nicely batched.

Were nearly able to ship it off to the GPU. However theres a bit of bit extra work we will eliminate.

Reducing pixel shading with opaque and alpha passes (Z-culling)

Most net pages have plenty of shapes overlapping one another. For instance, a textual content field sits on prime of a div (with a background) which sits on prime of the body (with one other background).

When its determining the colour for a pixel, the GPU might work out the colour of the pixel in each form. However solely the highest layer goes to level out. That is referred to as overdraw and it wastes GPU time.

3 layers on prime of one another with a single overlapping pixel referred to as out throughout all three layers

So one factor you might possibly do is render the highest form first. For the subsequent form, while you get to that very same pixel, check whether or not or not theres already a worth for it. If there’s, then dont do the work.

3 layers the place the overlapping pixel is not stuffed in on the 2 backside layers

Theres a bit of little bit of an issue with this, although. Every time a form is translucent, you’ll need to mix the colours of the 2 shapes. And to guarantee that it to look proper, that should occur again to front.

So what we do is cut up the work into two passes. First, we do the opaque cross. We go entrance to again and render all the opaque shapes. We skip any pixels which are behind others.

Then, we do the translucent shapes. These are rendered again to entrance. If a translucent pixel falls on prime of an opaque one, it will get blended into the opaque one. If it will fall behind an opaque form, it doesnt get calculated.

This technique of splitting the work into opaque and alpha passes after which skipping pixel calculations that you simply dont need known as Z-culling.

While it might look like a easy optimization, this has produced very massive wins for us. On a typical net web page, it vastly reduces the variety of pixels that we have to contact, and have been at the moment methods to maneuver extra work to the opaque pass.

At this level, weve prepared the body. Weve performed as a lot as we will to eliminate work.

And have been able to draw!

Were able to setup the GPU and render our batches.

Diagram of the four threads with compositor thread passing off opaque cross and alpha cross to GPU

A caveat: not every thing is on the GPU yet

The CPU nonetheless has to do some portray work. For instance, we nonetheless render the characters (called glyphs) which are utilized in blocks of textual content on the CPU. Its potential to do that on the GPU, however its arduous to get a pixel-for-pixel match with the glyphs that the pc renders in different functions. So individuals can discover it disorienting to see GPU-rendered fonts. We’re experimenting with shifting issues like glyphs to the GPU with the Pathfinder project.

For now, these items get painted into bitmaps on the CPU. Then they’re uploaded to one thing referred to as the feel cache on the GPU. This cache is saved round from body to border as a end result of they often dont change.

Even although this portray work is staying on the CPU, we will nonetheless make it sooner than it’s now. For instance, when have been portray the characters in a font, we cut up up different characters throughout all the cores. We do that utilizing the identical approach that Stylo makes use of to parallelize type computation work stealing.

Whats subsequent for WebRender?

We stay up for touchdown WebRender in Firefox as half of Quantum Render in 2018, a few releases after the preliminary Firefox Quantum launch. It will make todays pages run extra easily. It additionally will get Firefox prepared for the model new wave of high-resolution 4K shows, as a end result of rendering efficiency turns into extra vital as you enhance the variety of pixels on the screen.

But WebRender isnt simply helpful for Firefox. Its additionally vital to the work have been doing with WebVR, the place you’ll need to render a distinct body for each eye at ninety FPS at 4K resolution.

An early model of WebRender is at the moment accessible behind a flag in Firefox. Integration work remains to be in progress, so the efficiency is at the moment inferior to will in all probability be when that is full. If you would like to sustain with WebRender improvement, you’ll have the ability to comply with the GitHub repo, or comply with Firefox Nightly on Twitter for weekly updates on the entire Quantum Render project.

Lin is an engineer on the Mozilla Developer Relations staff. She tinkers with JavaScript, WebAssembly, Rust, and Servo, and in addition attracts code cartoons.

More articles by Lin Clark

Please check this great service at: or visit FREE SERVICES menu
[Total: 0    Average: 0/5]

3 thoughts on “The Complete Internet At Most FPS: How WebRender Removes Jank

  1. tru inox 304

    An impressive share! I’ve just forwarded this onto a colleague who had been conducting a little homework on this.
    And he in fact ordered me lunch due to the fact that I found it for him…

    lol. So allow me to reword this…. Thanks for the meal!!

    But yeah, thanx for spending time to discuss this topic
    here on your website.

  2. garbage disposer

    Have you ever considered writing an e-book or guest authoring on other blogs?

    I have a blog based upon on the same subjects you discuss and would love to have you share
    some stories/information. I know my audience would appreciate your work.
    If you’re even remotely interested, feel free to shoot me an e mail.

  3. join pak army through ssc

    Hello very cool blog!! Guy .. Excellent .. Amazing .. I will bookmark your
    site and take the feeds also? I am glad to seek out numerous
    helpful info here in the post, we want develop more techniques in this regard, thank
    you for sharing. . . . . .

Comments are closed.