 Our next speaker is Nicolas Silva and he comes from the Paris office. I kind of failed of finding jokes or strange things about his likes, so I will just go like if he's French, he will probably like cheese and wine, right? No, he will come from afterwards. I invite you to listen to Nicolas Silva. Thank you very much. Thanks. Can you guys hear me at all? Like, am I actually going through the speakers? All right, let's make sure that I am not on mute right now, I think. Yeah, I'm going to give you this one. All right, do I need to speak louder? Yes. All right, I will try to do that. Okay. Well, I'm sorry to advance. My voice is very, very broken. And my brain is barely in a better state. Well, do my best to talk about WebRender today. I'm going to talk a little bit before that about Firefox and how like the rendering engines in today's browsers work. So a little bit of an architectural overview and then I will talk about WebRender and what we're trying to do with this new shiny project. My goal here is really to see if, to share some experiences and maybe sparks some interest. And if you guys are interested in this topic, it's probably that we won't have time for a lot of questions in the end. So don't hesitate to find me after a talk and we should chat about these things, especially if you've been working on similar projects because I know that there are different open source projects that try to achieve similar goals. So here we go. WebRender. So before I go... Oh, this is much louder now. Okay. Before I talk about today's browser, I can give a little introduction on server, which is a project that is driven by the Mozilla Research Team, which I'm not actually part of. I like to work with them. They're really great and they have this beautiful logo. And it's kind of telling when it comes to like how much of a product we are trying to make that thing. The server is mostly research and it's really good. It's really great to try out new ideas and it would be very hard to try in Firefox because Firefox is a very big code base with some amount of technical debt. And so having this research browser where we can try out new ideas and work out code and not really worry about users at all is really, really nice. And this is the reason we can have things like WebRender today. Now, let's talk a little bit about what web browsers do today when it comes to rendering. So this is a bit of a loaded slide. Can you guys all see it? Yes, okay. The interact with the DOM. And so in the rendering engine, we have a representation of the DOM, which is just a tree of nodes that only have positions. There needs to be computed and when this is computed, you obtain what we call a frame tree. Other browsers like Chrome and WebKit tend to call this the flow tree, I think, but it's pretty much the same. From this tree of positioned elements, Firefox will build what we call a display list, which is a flat-ish list of what we call display items, which are things that know how to render themselves. And the kind of display items that you can get are like image display item, bordered display item, text, things like that. And it's not actually a list. It's like, so you can have like a shoulder display item that contains another display list inside of it, but it's mostly like a list. It's pretty flat. And so far, we haven't actually rendered anything. We've just built some representation of the page that is closer and closer to what we actually want to use to render things. So you take this display list and we render it in a layer tree. A layer tree, think of it as those layers in Photoshop. They're intermediate surfaces that contain the actual rendered content. And we move that as a tree in order to be able to say, okay, there's going to be this header there which is going to stay there and the content of the page is going to just move underneath it for scrolling and transforms and such. And so this is where we have this compositing infrastructure. And until this limit there, we're all in the content process, but this layer tree is not actually brought to the screen in the content process. We'd share it with the compositor process and then we do what we call the compositing, which is a reaction of taking all of those layers and flattening them on the screen. And we try to do that at 60 FPS. The painting at 60 FPS is pretty challenging. So it's very useful to be able to separate the painting from the compositing and be able to scroll at 60 FPS. This architecture comes from how CDs used to work a while ago. It's a pretty sound architecture, actually. However, if we want to use the GPU, we can actually do things differently. So this whole architecture that most browsers are using, having really been designed to take full advantage of the GPU. One of the ways this manifests itself is in the way that, for instance, the specialists will have these algorithms who know how to render themselves, but they won't actually know how to optimize themselves by looking at the rest of the algorithms, which is something that you really need to do efficiently in the GPU. So what about the render? Well, the render is sorry about this. The render is in time to move away from this type of architecture and do something that is different that's designed around using the GPU. So the architecture of the render is kind of like a game rendering engine, which has some advantages that I'll talk about at the end of the talk in time. We don't actually do a distinction between the compiling and the painting. We just render everything on the render directly. So that would be on what we used to call a compositor process. But now we would call, I guess, the render process. I don't know, the main process. So we take this items and we just use that as the source of information to build commands that we send to the GPU and then we send them to the GPU. If you look at what we can do, the types of things that you have to render on the web, a lot of them can be seen as access in line with tenders that are pretty easy for a GPU to understand and work with. So we try to turn all of that information into as much as possible, something that the GPU can understand. It's really a pleasure for now, whenever we get to actually ship it to users in Firefox, it will probably have other backings, but right now we're focusing on having only one so that we can still experiment and move quickly. This is still very much a work in progress. Web rendering doesn't support all of the features that we need right now. So the way we go about, for instance, integrating this into Firefox is to say, okay, we have two rendering systems and for everything that WebRender supports, the way we render for the rest, we will still use a very rendering system and many of these things in images and then uses images in WebRender. It's really rust, which is sort of irrelevant to sort of the, I wanted to talk, but I just wanted to mention it because it's a pleasure to work with this language. I really love it. And something else that is very important in the design philosophy of WebRender is that it's designed to focus on the primitives that are most common in the Web. So where some APIs will try to sort of the hard problems first, like drawing arbitrary shapes with anti-aliasing, like different kinds of patterns and things like that, like carol or ski I would do. WebRender doesn't even support arbitrary shapes. It can only understand things that are very common in the Web, like rectangles, rounded rectangles, images, blurs, and things like that. And so this is really important because this is actually how we get most of our performance by simplifying the problem and finding the solution that works best with this simplified problem. So how do we mix things using the custom GPU? And then the important thing is that GPU APIs, especially the sort of OpenGL, D3D, DEM11, AI APIs, are really bad at submitting a lot of droplets. And so somewhere in our rendering engine, we'll have to be smart about not sending too many of them. So batching is the key word here. GPUs are very sticky things. And switching between states is very expensive. So for instance, if you're rendering into a surface and you want to render it to another surface and then the batch rendering on the first surface, it's very expensive to switch between these surfaces. So your batching also needs to sort of take into account that minimizing those state changes is really important. Transferring data to the GPU, from the CPU to the GPU and whatever you're rendering on is also very expensive. So then you have to design a system around trying to avoid sending too much data. Or if you need to send a large amount of data, it should stay on the GPU if we're going to reuse it in the next frame. And one thing that is good about what rendering is that it knows that it's going to have more frames. And so the API and the sort of architecture is designed to take into account the fact that most of your next frame is going to be like the current frame. So the resources that you are building are expensive to build should stay on the GPU and be able to use. Another thing is that memory bandwidth is really costly, especially on mobile devices, which tend to have a very, very high density pixel, or screens, sorry. And so we should strive to avoid touching too many pixels, or we should strive to avoid touching the same pixels too many times. If we're going to cover that pixel, it's probably not worth drawing the thing that is underneath the tennis primitives that would actually cover it. So overall, and overall it's a pretty high thing to solve for many of the rendering APIs. So designing around that is also a good thing. So we'll do other web pages. Let me do it actually pretty simple when you think about it. It's a lot of work tables, rounded ones, rounded ones that are actually so permanent that you really want to have a specific primitive for them, rather than building a path that has arcs and feeling that. I think that is actually very important. We have images obviously. We don't actually have optimizations for cat pictures, but maybe something. We have shadows. And we have borders and a bunch of other stuff, but generally the amount of primitives that you have on the web is pretty small, pretty small. So this is a screenshot of the did-have-bridge of the survey project. Oh, we're running a project, actually. So you can see that it's mostly the tangles, borders, and text obviously, very important. And what we're going to understand is that it's two shader primitives. We need shaders to map to those really basic primitives that you see on the web. So we have side power. We have images, what are the images? I'm not going to actually, like, sort of, we can do the slide. It's not very ingesting itself, but what's interesting is actually that it's just it maps to the things that primitives are having on the web. And it doesn't try to be more generic than those primitives. Whether or not the moment doesn't support arbitrary, like, SUG paths. So it's still something that we're working on. So if you're wondering what I would fit there, well, it's still an interrogation mark. The shaders on the web are not somewhat... Sorry. I don't know how I trigger those sounds. I'm very sorry. The way the shaders work in the web number is it's pretty much like a video game except that in a lot of video games you probably put a lot of data in the vertex data and sort of, like, arbitrary meshes and shapes and both sort of your visuals around the shape of the geometry that you send around. And in one way or another, we try to work as much as possible with rectangles. And if their axis aligns, it's even better because it simplifies a lot of things. So the vertex geometry that you send is actually very, very simple. It's just a quad with similar coordinates, like X and Y. It's a unit quad that you send. And you use instancing to render the menu primitive. So, for instance, if you need to render, say, 100 rectangles, we'll just use that quad that is on the GPU and say, yeah, 100 times with instancing. And in the vertex shader, you see there's this unit quad and it's not actually positioned at all. And you have an instance ID. And you use this instance ID to look up the information we need and some buffers or textures. The really, really detailed of, like, starting these is a bit, like, a moving piece, but you tend to sort things into textures so we can have an arbitrary amount of data and also because of some, I think, driver bugs and constraints that we had. Really beautiful buffer. Sorry, buffer objects. So, yeah, the vertex shaders, most of them look pretty much the same. The later primitives, they apply, they transform, they apply a clip. It's actually quite important to have at least one clip applied to all primitives because we want to make sure that, for instance, no drawing primitive can go out of, like, the rectangle of the look content. So, every primitive actually has at least a rectangular clip and it's applied in the vertex shader in most cases, which is actually very easy because you have your vertices that you're positioning in bold space and you just need to clamp the coordinates to the inside of that bounding rectangle that defines your clip. So it's actually pretty easy. And we apply the transform, so there's two types of transform. There's the position of the rectangle and the space of its stacking context. The stacking context is, raise your hand. All right, so I'm using words that are very, very specific to the implementation of web technology. The stacking context is sort of a frame of reference for coordinates in the web page. This is a low simplification, but it says that the terminology that we would use in the web specifications do talk about that. So, for instance, if you have something that can scroll around, there is a stacking context that defines that frame of reference that moves in the page. Whereas something that will be position fixed will have its own stacking context which is going to be different from the thing that is scrolling around. And so, back to the vertex shader, we apply the position to our unit grid. So it's in the reference of its stacking context and then we apply a transform that is the transformation of that stacking context. So if you have a transform, like scrolling, for instance, will be one of these transformations that we'll have a specific transformation for. And so we end up with the vertices position in the right place and you have some primitive data that we can then send to the fragment shader. And the fragment shader just computes the color that's specific to each shader. So, for instance, the unit shader is just going to, like, load, essentially, data from the texture and the solid color of the fragment shader is just going to paint the color and start in the primitive. The primitive thing is a very, very important topic. So I was saying that everything is bad and that we should try to avoid it, especially for, you know, four-case screens and whatnot. And Oak Ridge and Cone is how we do it. So this is actually a bit of a moving piece. We moved to this in December, like less than a few months ago. We used to have some CPU-side software occlusion-colored scheme that we just ditched for using the Z-buffer, which is actually a very simple thing and it's extremely efficient. It's way more efficient than it thought it would be at first, actually. And so we used the Z-buffer. It was just like a game engine would use the Z-buffer. We send a Z-coordinate to our primitives. The Z-coordinate is actually the painting order. So it's a bit like the Z-index, but it doesn't actually map, it needs to map to the actual Z-index values. And we're going to do a first part, so all the open objects are going to be rendered front to back and then all the potentially transparent objects are going to be rendered next back to front. And we're going to use the Z-buffer to try to avoid painting pixels that have already been rendered by something that is more front. And that makes any sense. And so this technique is nothing new. Really, games have been doing that forever, especially 2D ones that use the GPU. And we're using that technique because the speed up that we got from using that was glorious. So batching is also very important. I already said it, and it needs to take into account this order that is applied to the transparent primitives. But it also needs to take into account the avoiding state switches and things like that. So for a quick primitive, it's actually very easy because we can render them in any order. We try to render them front to back to avoid painting pixels that are going to be colored later. But if we can say, if we can avoid breaking batches, we'll probably decide to render them in a different order, like render all of the objects and then all of the images rather than, you know, front to back strictly. For the transparent path, it's a bit trickier because we need to know things that overlap we can't really do them in any order, and that makes sense. I'm going to wrap up quickly. But before that, I'll just give an example. So this is some contrived hypothetical web page and the rectangles are solid parts and the shapes that are not rectangles are potentially transparent. Imagine that just going to your using and forcing us to treat them as potentially transparent objects. And so we have the circle primitive and the triangle primitive, which will actually exist in WebNet. This is just an analogy, and I'm sorry, I'm a little bit late. And so we're going to start with the frontmost rectangle and then go all the way down beneath it. And so we have drawn all of the rectangles. And by doing so, like when you render this big yellow thing there, we're actually retouching a lot of pixels that we would have if we were painting back to front. And then we really start rendering the transparent things sort of back to front. But actually that's primitive number two here. Should have been first, but since we can detect that they don't overlap, we can just back to front so that we can first render that triangle and then render the other two in the same batch. I'm just going to skip that thread because it's not as important as the one I'm making. Great. So, what we know, things were listening to my talk. If you have any questions, don't hesitate to... I'm only going to be outside so that people who are interested can ask questions. Maybe I'll have a little bit of time for questions. One or two questions. One or two questions, okay. Well then, let's go for questions then. Can you please repeat the question? The question that I understand in the studio is what render doesn't support mobile GPUs? Is that... I don't know what's that, the question? The question is which mobile CPUs are supported and how do we deal with those that won't be able to support? So, as far as webinar is concerned, we tried to target a 3 to 10 level of GPU API. So, it's GIS 3.1 1,000,000 don't quote me on the exact approaching number there, but it means that we can support a lot of mobile GPUs. But, there's only going to be crappy drivers because drivers are really hard to write and they tend to do that. So, there needs to be a feedback and whether or not it doesn't have a software feedback. So, as far as high-fives is concerned, it's going to just use experienced rendering architecture when the rendering doesn't work. Can you say a few words about the new front rendering engine in the web rendering? Could you please say a few words about the new front rendering engine in the web rendering? The front rendering. So, front rendering is a bit of a moving piece, but right now, I'm going to do the question. So, if you were about the front rendering, the front rendering is a bit of a hard topic because as soon as you do the rendering, that doesn't look exactly like what the OS provides. People will be really, really mad. They will take turns to yell at you when they're far by this. And so, for each platform, we have actually a different front rendering mechanism. So, it's going to be very platform-specific. We also have some people doing research about doing the front rendering directly on the GPU. There's the Pathfinder project which is very promising, but it's very early, so not something that I would ship right now. Lots of moving pieces. So, it depends on the platform. For instance, on Linux, what we would do is use free type and have a thread pool that is actually might slide down. We have a graph renderer thread which will do the graph rendering asynchronously and use a thread pool to empower as much as possible. And we will put these graphs to the GPU and we store them in a cache and then we treat that as a sort of like image, but it's not actually treated as a special shader for graphs because we need to be able to support separate SanTi's in which you can do a bit of filtering in the shader. Does that answer your question? That's welcome. Alright, thanks very much. I'll pass it to you in a minute.