Verso: Writing its own compositor part 2

Wu Yu Wei published on
4 min, 713 words

In the previous post, we extended the embedder to handle more jobs like thread and channel creations. We also tried to communicate with Constellation directly to reduce the overhead. In this post, I'll demonstrate how we implemented our own compositor that fits our needs. This part may seem like just writing the same module, but I believe it did more than that and established a solid foundation to support multi-surface in rendering context.

Clarify which component should own which states

One of the major goals of the custom Compositor is to figure out which state should stay in which type. Because we are going to use the same rendering context with multiple surfaces to achieve multi-window support, this means the rendering context should, of course, belong to the Compositor. This also means all the types around webrender will stay in the Compositor. However, other fields that are not GL-related should be removed from the Compositor, and it should only get access to them when it's necessary. So here are some major fields that got removed, and I'll explain the reasons.

Window

This field is very obvious because we want to support multiple windows in the future, so the Compositor shouldn't own only one window in its field. In Servo's compositor, it uses WindowMethods to get the generic of the Window. Its trait methods cause a little overhead because they are not granular enough. For example, when it wants to get the viewport size, it always needs to get the whole EmbedderCoordinates. And the rendering_context forces the window to hold a copy of the rendering context as well. The Compositor should only get access to a window in methods when it really wants to get the states of the window. After removing, it also helps the window type remove some redundant types.

Webview

A webview is essentially an alias of a top-level browsing context. Previously, the Compositor had a WebViewManager to handle them, but now it's removed. This sounds a bit weird but let me explain. In the multi-window environment, I would prefer a window that contains and manages the web views instead of the compositor. If the Compositor wants to know the painting order of webviews for the current frame, it can ask for Window::painting_order to get the order the window wishes to composite. It will be the Window to actually own its WebView. This will also be the same when we introduce more window types like headless windows in the future.

CompositeTarget

CompositeTarget was used for checking what's the target that the Compositor should display. So it can render to offscreen framebuffers or create images in shared memory instead. However, this creates additional texture and framebuffer objects that are not owned by the RenderingContext. This makes it difficult to figure out what are all these GL objects that the compositor is handling. It should be the job of rendering context to tell the compositor which exact surface it should use. So, right now, they are all removed, and there's only one single surface in the rendering context that needs to be handled. We will extend the functionality of rendering context to support multiple surfaces in the next part.

The next step

With the custom compositor added, the current Verso instance workflow remains the same. For each run iteration, it will handle the winit event first and then handle servo messages from the Constellation. But this time, it's the Window and the IOCompositor working with each other to handle all the messages from the Constellation. The next step will be the most significant step: We will extend the rendering context to support multi-surface. And if it works perfectly, it should enable us to implement multiple windows with a single context. We are close to complete the journey, stay tune for the next and hopefully the final part!