Chromium Viz 浅析 - SkiaRenderer & SkiaOutputSurface

 

Manuscript source: Alibaba Cloud Developer Community

 

Some of Chromium's main performance optimization projects for rasterization and compositing include OOPD (Out of Process Display Compositor), OOPR (Out of Process Rasterization) and SkiaRenderer.

We introduced OOPD in Chromium Viz Analysis-Synthesizer Architecture . Its main purpose is to migrate the Display Compositor from the Browser process to the Viz process (that is, the original GPU process). Browser has become a Client, Renderer of Viz. Establishing a link with Viz (CompositorFrameSink) is still through Browser, but submitting CompositorFrame after establishing a link is directly submitted to Viz. Browser also submits the CompositorFrame to Viz, and finally generates the final CompositorFrame in Viz, which is then synthesized and output by the Renderer through Display.

In the Chinese translation of How cc Works , we briefly mentioned OOPR. The main differences between OOPR and the current GPU rasterization mechanism are:

  1. In the current GPU rasterization mechanism, when the Worker thread executes rasterization tasks, it will call Skia to convert 2D drawing instructions into GPU instructions. The GPU instructions issued by Skia are transmitted to the GPU thread of the Viz process through the Command Buffer for execution;
  2. In OOPR, when the Worker thread executes rasterization tasks, it directly serializes the 2D drawing instructions (DisplayItemList) to the Command Buffer and transmits them to the GPU thread. The part running on the GPU thread then calls Skia to generate the corresponding GPU instructions, and sends them to the GPU thread. Directly executed by the GPU;

In short, the part of Skia rasterization is transferred from the Renderer process to the Viz process.

In the next part of this article, we will analyze SkiaRenderer and SkiaOutputSurface.

DirectRenderer & OutputSurface

Before continuing to analyze SkiaRenderer and SkiaOutputSurface, let's briefly introduce their base classes  DirectRenderer  and  OutputSurface .

As the name implies, DirectRenderer is used by Display to synthesize and output the final CompositorFrame. It traverses each RenderPass in the CompositorFrame, traverses each DrawQuad in each RenderPass, and generates corresponding drawing instructions for each DrawQuad. The OutputSurface is used to provide a target Surface for the final composite output. For the Renderer, its main function is to provide a drawing context for the Renderer.

Before SkiaRenderer, we synthesized the GPU, Renderer using  GLRenderer , as the name implies, it generates a drawing instruction for each instruction DrawQuad GL is that it requires OutputSurface ContextProvider as a drawing context, it may be acquired based on a Command Buffer by ContextProvider GLRenderer GL interface, and then issue GL commands through the GL interface.

There was a DelegatingRenderer in history, which corresponds to DirectRenderer, but after the application of the new synthesizer architecture, DelegatingRenderer is no longer needed, so now there are only DirectRenderer and its derived classes.

SkiaRenderer & SkiaOutputSurface

When we turn on OOPD, the Display Compositor runs on the Viz Compositor thread of the Viz process, which means that it is the same process as the GPU thread. In theory, there is no need to use the Command Buffer, although the current GLRenderer still needs to use an InProcessCommandBuffer. Make cross-thread GL instruction calls. The SkiaRenderer allows us to completely avoid the use of Command Buffer in the synthesis process.

Corresponding to GLRenderer  , the drawing instruction generated by SkiaRenderer for each DrawQuad is a Skia drawing instruction, which is output through the SkCanvas provided by SkiaOutputSurface. SkiaOutputSurface has two derived classes  SkiaOutputSurfaceImpl  and SkiaOutputSurfaceImplNonDDL. SkiaOutputSurfaceImplNonDDL should be just a transitional implementation of the special synthesizer architecture of Android WebView used in the reconstruction process, so we focus on the explanation of SkiaOutputSurfaceImpl.

Earlier we mentioned that Display Compositor runs on the Viz Compositor thread, which calls SkiaRenderer, but the GPU instructions output by Skia must be executed on the GPU thread. So in fact, for the SkCanvas provided by SkiaOutputSurfaceImpl to SkiaRenderer, its target SkSurface is not the SkSurface that is actually used for the current output, but a Compatible SkSurface. SkiaOutputSurfaceImpl uses the characteristic information of the final SkSurface to generate the SkDeferredDisplayListRecorder, and then obtains the SkCanvas provided by the SkDeferredDisplayListRecorder. The drawing instructions output by the SkiaRenderer through the SkCanvas are actually stored in the SkDeferredDisplayList inside the Recorder.

When SkiaRenderer finishes drawing a RenderPass, SkiaOutputSurfaceImpl strips the corresponding SkDeferredDisplayList from the SkDeferredDisplayListRecorder, and then passes it to the SkiaOutputSurfaceImplOnGpu waiting on the GPU thread through the Post GPU Task, and then the SkiaOutputSurfaceImplOutput on the real DisplaySkurfaceSurfaceImplOnGpured will be output to the DisplaySkurfaceSurfaceImplOnGpured.

Promise SkImage

Promise SkImage is a very interesting concept. It was introduced mainly because SkiaRenderer runs on the Viz Compositor thread and does not have a GPU context, so when it needs to draw a picture, it cannot access the GPU resource corresponding to the picture at this time, but in fact The picture is again a reference to a GPU resource. However, because SkiaRenderer is first drawn to SkDeferredDisplayList, and then SkDeferredDisplayList is played back on the GPU thread, Promise SkImage is introduced to solve this problem.

Promise SkImage is actually a placeholder, it contains some meta information used to locate the corresponding GPU resource and a set of callback function pointers. When SkDeferredDisplayList is being played back, when the Promise SkImage needs to be drawn, these callback functions will be called Perform Fulfill, the Fulfill callback function will return a SkPromiseImageTexture containing the corresponding GPU resource information for Skia to use.

So Promise SkImage is actually-" Make a promise, and fulfill in future ".

Next BIG Thing

Just replacing the original GLRenderer with SkiaRenderer does not bring any performance advantages immediately. It is true that SkiaRenderer does not need to use Command Buffer, eliminating the overhead of Encode/Decode, but the overhead of Skia itself is not small, and it is difficult to say how much performance improvement is compared between the two. Therefore, SkiaRenderer is more together with OOPR to lay the foundation for subsequent further rendering performance optimization.

We can see that when OOPD, OOPR and SkiaRenderer are all turned on:

  1. Rasterization and synthesis have been moved to the Viz process;
  2. Rasterization and compositing both use Skia for 2D rendering. In fact, all of Chromium's 2D rendering is ultimately handed over to Skia, and Skia generates the corresponding GPU commands;
  3. During rasterization and synthesis, Skia's final output GPU instructions are all on the GPU thread, and use the same Skia GrContext (the internal GPU drawing context of Skia);

This means that when Skia supports Vulkan, Metal, DX12 and other 3D APIs, Chromium can decide which GPU API Skia uses for rasterization and synthesis according to different platforms and devices. Compared with GL API, Vulkan, Metal, DX12, these lower level 3D APIs, can bring lower CPU overhead and better performance.

 

Manuscript source: Alibaba Cloud Developer Community

 

 

Guess you like

Origin blog.csdn.net/weixin_40050195/article/details/98492902