Impeller, the New Flutter Rendering Engine
In this article, dive deeper into Impeller. Learn more about a cutting-edge custom-built engine that redefines the role of Skia.
Join the DZone community and get the full member experience.Join For Free
What Is the Rendering Engine?
The Flutter engine represents the core component of the Flutter framework responsible for rendering the user interface (UI) and displaying it on the screen. It maintains a tree of rendered objects, such as widgets and layouts, which are responsible for defining their own layout, painting their visual representation, and handling input events. The rendering engine in Flutter performs two main processes: layout and paint. In the layout phase, the engine analyzes the render object tree to determine the size and position of each element/object based on the constraints provided by the parent. Once the layout phase is complete, the engine analyzes the tree again, instructing each render object to paint itself onto a canvas.
The rendering engine in Flutter takes advantage of hardware acceleration and optimizes performance by minimizing unnecessary repaints. This allows for high-performance graphics rendering and smooth animations. By leveraging the capabilities of the rendering engine, Flutter enables developers to create fast and fluid user interfaces across different platforms and devices.
However, although all of this sounds great and promising in theory, in practice it has been shown that the current Flutter engine (Skia) has certain issues related to shader compilation on iOS. The problem occurs when the application is first launched before the shaders are cached and need to be compiled for the first time. This is particularly noticeable on slower phones.
What Is Skia?
Skia is the default Flutter rendering engine for Android and was the default engine for iOS until recently, up until version 3.10. Skia is a 2D graphics library used by Flutter for rendering the UI. It supports shaders, which are applied to different objects, shapes, or text. These shaders are compiled and executed on the GPU at runtime. The cause of the aforementioned problem lies precisely in this last sentence.
The generation and compilation of shaders happen sequentially based on demand, and this process can take several hundred milliseconds, which is much longer than the 16 milliseconds required to render a single frame at 60 fps. As a result, the compilation process can cause significant delays and a drop in frame rate from 60 fps to 6 fps, known as "compilation jank."
This problem has been present within the Flutter framework for quite some time, despite a considerable number of related issues on the GitHub repository. However, somehow this problem has been swept under the rug by the decision-makers who determine the priority of issues regarding the Flutter framework. That was the case until recently, specifically at the beginning of May last year (2022), when it was mentioned that there exists an experimental branch dedicated to a rewrite of their graphics backend. It was stated that it would take many months before that project becomes stable enough for production use. Luckily for us developers and all others who use our applications, that ambitious but much-needed project has reached its conclusion and has taken shape. This project or new Flutter rendering engine is called Impeller.
What Is Impeller?
Impeller is a new Flutter rendering engine that the Flutter team claims solves the early-onset jank problem. It is designed as a replacement for Skia, with the goal of enabling better animations and addressing the "jank" issue, while also potentially providing support for 3D, which was not previously possible with Skia, as it exclusively supports 2D. Furthermore, it's important to note that Impeller is designed to fully harness the advantages of modern accelerated graphics APIs like Metal and Vulkan, maximizing their capabilities. What sets it apart from Impeller and essentially solves the mentioned problem is that Impeller performs the majority of shader compilation ahead of time.
Unlike Skia, Impeller compiles shaders during the build process instead of at runtime. During the build process, the Impeller shader compiler (impellerc) is used to compile GLSL (OpenGL Shading Language) code into SPIRV. GLSL is a high-level shading language utilized for programming shaders in OpenGL and OpenGL ES. On the other hand, SPIRV is an efficient representation for shader code that is not limited to OpenGL and OpenGL ES but can be used with other graphics technologies as well. impellerc performs the conversion of GLSL code into SPIRV to enable cross-platform compatibility and efficient execution of shaders. The behavior of shader compilation is controlled by passing flags to impellerc. The output of the compilation is a binary blob in the form of a SPIRV module, which can be loaded and executed by a graphics driver or runtime. As a result, these SPIRV modules (binary blobs) can be executed on various platforms.
This significantly reduces the initial app startup time and eliminates shader compilation jank. Additionally, it is important to note that the Flutter team states that this approach reduces the APK/IPA size, which will be another significant benefit of this engine.
As far as it is known, Impeller will have support for iOS, Android, Desktop, and Embedder API users, which primarily indicates support for all platforms targeted by the C++ engine. This suggests that Impeller is not intended to support the web platform.
Impeller on iOS
Impeller will be the default rendering engine for all iOS applications developed in Flutter starting from version 3.10. If, for any reason, a developer does not want to use Impeller and prefers to continue working with Skia, it is possible to disable Impeller for debugging by using this command:
flutter run --no-enable-impeller
Or if you want to disable Impeller while deploying your iOS app, add this to Info.pllist:
Impeller on Android
Although the support for Android is not yet stable and not ready for preview, the Flutter team mentions that there is a possibility that Impeller may not function properly on the master channel. However, it is possible to try out and experiment with Impeller on Flutter 3.7+ stable versions. You just need to add this application tag to the AndroidManifest.xml:
<meta-data android:name="io.flutter.embedding.android.EnableImpeller" android:value="true" />
Run the app by executing the following command in the terminal:
flutter run --enable-impeller
Opinions expressed by DZone contributors are their own.