Impeller, as the new rendering engine of Flutter, is responsible for drawing the interface of the application, including layout calculation, texture mapping, animation processing, etc. It will convert the code into pixels, colors, and shapes, so Impeller will have a direct impact on the performance and rendering effect of the application, which is the reason why many of the early Flutter developers who upgraded from Skia to Impeller often encountered pain points. This is also a pain point that many early Flutter developers who upgraded from Skia to Impeller often encountered, for example:
Fonts load abnormally, glyphs and typography are not correct as before, e.g. #142974, #140475, #138670, #138386
Inconsistent line rendering or cropping, e.g. #141563, #137956
Certain textures synthesize flickering/deformation, such as #143719, #142753, #142549, #141850.- —-
As you can see, Impeller has a lot of bugs that need to be dealt with on the way to replacing Skia, and even a lot of problems that have been fixed on Skia have to be fixed again on Impeller, so why does the Flutter team still want to switch Skia to Impeller? Was Skia not good enough?
First of all, Skia is certainly an excellent general-purpose 2D graphics library, for example, Google Chrome, Android, Firefox and other devices use Skia, but also because of its “generality”, it does not belong to the shape of Flutter, it can not be optimized specifically for the requirements of Flutter, for example, many of the features attached to Skia are beyond the requirements of Flutter. For example, Skia comes with many features that exceed Flutter’s requirements, some of which may lead to unnecessary overhead and slower rendering times, and as of now, Skia’s generality creates a performance bottleneck for Flutter.
Impeller was created specifically for Flutter, and its main core is to optimize the rendering process of the Flutter architecture. Its rendering method can make more efficient use of the GPU on Flutter than Skia, allowing the device’s hardware to render animations and complex UI elements with less work, thus increasing rendering speed.
Additionally Impeller uses tessellation and shader compilation to decompose and pre-optimize graphics rendering so that Impeller can reduce the hardware workload on the device, resulting in faster frame rates and smoother animations.
Unlike Skia, which dynamically compiles shaders on Flutter, which can cause rendering delays, Impeller compiles most of the shaders ahead of time, which significantly reduces lag during animation because the GPU doesn’t have to pause while rendering frames to compile the shaders.
Impeller also simplifies the rendering process with a new layered architecture that allows each component of the Engine to perform its specific task with maximum efficiency, reducing the number of steps required to translate Flutter widgets into pixels on the screen.
Therefore, Impeller was designed with a layered structure where each layer builds on the next to perform specialized functions. This design makes the engine more efficient and easier to maintain and update because it separates different concerns.
First, the top layer of the Impeller architecture is Aiks, a layer that primarily serves as a high-level interface for drawing operations, accepting commands from the Flutter framework, such as drawing paths or images, and converting these commands into a set of finer-grained “Entities” that are then passed on to the next layer.
The next layer under Aiks is the Entities Framework, which is the core component of the Impeller architecture. When Aiks generates Entities from the commands it processes, each Entity is actually a separate unit of the rendering command that contains all the information necessary to draw a particular element.
Each Entity has properties such as a transformation matrix (encoding position, rotation, scaling) and a content object that holds the GPU commands needed for rendering. These content objects are very flexible and can manage a number of UI effects such as solid colors, images, gradients, and text, but at this time, Entities can’t act directly on the GPU. At the time, Entities did not work directly with the GPU, as the Engine still needed to communicate with Metal or Vulkan.
The Hardware Abstraction Layer (HAL) is the foundation of the Impeller architecture. It provides a unified interface to the underlying graphics hardware, abstracts the details of the different graphics APIs, and ensures Impeller’s cross-platform capabilities by converting high-level rendering commands to low-level GPU instructions, acting as a This layer ensures Impeller’s cross-platform capabilities by translating high-level rendering commands into low-level GPU instructions and acting as a bridge between Impeller’s rendering logic and the device’s graphics hardware.
As we all know, the most time-consuming tasks in a rendering engine are the rendering pipeline and shader compilation. The rendering pipeline is a series of steps in which the GPU performs the rendering of graphics, which are generated and processed by the HALs, so the HALs also play a very important role in performance.
Additionally, as mentioned earlier, Impeller pre-compiles most shaders in advance, a strategy that significantly reduces rendering latency and eliminates lag associated with dynamic shader compilation, and this pre-compilation occurs during the build of the Flutter application, ensuring that shaders are available as soon as the application is launched
And while pre-compiled shaders would normally result in a dramatic increase in app startup time and app size, because Impeller is built for Flutter, Impeller’s shader pre-compilation can rely on a simpler set of shaders than Skia’s, keeping app startup time short and overall size not increasing dramatically.
Finally, if you’ve been using Flutter for any length of time, you should know that Anti-Aliasing and Clipping are expensive operations, and these are optimized under the hood in Impeller.
Antialiasing in Impeller is addressed by multisampling antialiasing (MSAA), which works by sampling each pixel multiple times at different locations within the pixel, then averaging those samples to determine the final color, and finally blending the edges of the object smoothly with its background to reduce its jagged appearance.
For clipping operations, Impeller manages the clipping process using a stencil buffer (a component of the GPU). When Impeller renders the UI, it first lets the GPU use the stencil buffer, which primarily acts as a filter to determine which pixels should be displayed instead based on the clipping mask, and then optimizes the stencil buffer. Finally, by optimizing the stencil buffer, Impeller ensures that clipping operations are performed quickly.
So, now you understand the Impeller advantage?
While there are still details to be optimized for the switch from Skia to Impeller, it should come as no surprise that Impeller will be the default engine for Flutter on Android and iOS in 2024, and Skia will most likely say goodbye in 2024, so are you ready for Impeller’s baptism of fire?