Vulkan API as a predictable and efficient way of building automotive HMIs

Posted

May 15, 2020

Authors
Filip Wasil
Series

Safety has always been a priority when it comes to automotive software development. As for decades, we observe the market itself changing rapidly, and there is still this one thing that remains as a concern — The car has to be safe. This has an impact on the way the software is designed. It affects the way it’s written and affects the tools we use to help us do the job. Safety requirements affect all the software layers — starting from the lowest kernel module areas, and ending up in the presentation layers.

Writing a cluster UI or an infotainment application usually means dealing with high-level abstraction introduced by the editors and libraries. Regardless of which one we are using, they all must have a module communicating with the Graphics processing unit itself — using a driver Application Programming Interface (API). The most commonly used driver interface used for accessing GPU features is OpenGL. It makes it possible to implement various graphical effects using relatively simple GPU access calls because complex low-level operations will be hidden behind a lot simpler abstraction.

This abstraction is meant to be easy to understand, for the programmers and the tool designers. However, there is this well-known rule about the abstraction — It always comes without a cost. The higher the abstraction level we have, the less aware we are of what is going on, the more we rely on the implementation we have no access to, and the less customizable our software is.

These are one of many reasons why the market is looking towards something better, looking for a more efficient and safe way of accessing GPU resources. And here is where the new generation interface — Vulkan — starts to shine.

Pic. 1. Instrument Cluster rendered using Vulkan — metal style

Predictability and performance

As you may guess, driver quality has a lot of impact on the overall application performance. The OpenGL driver is a complex piece of software which due to the way it is designed, has to manage the GPU access context internally. This impacts three major critical aspects of automotive area:

  • predictability
  • efficient rendering pipeline
  • resource usage transparency

Starting with the first point — if we do not have the driver code in case of any errors, performance problems, or optimizations related to the driver — we are on our own. From version to version, from one hardware to another one, we rely on the different quality of the driver implementations. Our control over the application is becoming limited. In some cases, this may be critical not only for the system efficiency but also for its stability.

In automotive, we are dealing with cases where there are multiple operating systems running in parallel on one single hardware platform. If these OSs are sharing resources — these resources have to be managed. OpenGL based driver is not exposing this information, and we may have hard times to predict how much memory we still have available.

Vulkan’s design addressed all of these problems. This modern API driver is by design much less complicated comparing its ancestor. Application using Vulkan introduces much less risk when moving it across different hardware platforms or when upgrading the driver version. It allows the application author for a lot more optimizations and makes it possible to monitor GPU resources usage and workload much more precisely.

Pic. 2. Monitoring GPU workload and Memory budgets in real-time

Pic. 3. Monitoring GPU workload using Vulkan — real-time charts

Just like in the OpenGL case, we still can use advanced frame debugging tools like Renderdoc. We can capture and analyze details of our rendering pipeline setup, including performance counters, input, and output images and viewing the rendering operations in a timeline and sniff general rendering statistics if needed.

Pic. 4. Frame analysis using RenderDoc tool and Vulkan application — input/output images view

Pic. 5. Frame analysis using RenderDoc tool and Vulkan application — geometry view

*** Statistics viewer ***File size: 191.51MB (481.42MB uncompressed, compression ratio 2.51:1)
Persistent Data (approx): 0.02MB, Frame-initial data (approx): 481.37MBDraw calls: 9
Dispatch calls: 0
API calls: 17
API:Draw/Dispatch call ratio: 1.88889
12 Textures — 469.75 MB (469.75 MB over 32x32), 5 RTs — 40.55 MB.
Avg. tex dimension: 2642.29x2642.29 (2642.29x2642.29 over 32x32)
6 Buffers — 0.73 MB total 0.05 MB IBs 0.68 MB VBs.
511.03 MB — Grand total GPU buffer + texture load.

Validation layers

The software development process always includes certain methods to deal with potential software issues. This is why we introduce processes, we continuously test what we create, setting up CI servers, or we write unit tests. We have to deal with the fact that mistakes happen. One fact about them is that the longer it takes us to detect one, the more costly they may become. Therefore it is always better to detect any potential issues as early as possible. The same applies to graphics applications. OpenGL way of dealing with errors is very simple but has several problems:

  • no extend-ability of the error handling system
  • poor verbosity
  • non-accessible error handlers

Vulkan introduces the concept of validation layers. It is a set of optional software components that validate all Vulkan function calls. They find not only errors but also potential issues and misalignment’s in-memory operations. Any kind of issues or undefined behaviors is explicitly pointed out together with a potential solution and hints on how to deal with it. Vulkan API is explicit and very strict when it comes to setting states and allocating GPU memory. Among that — it makes it possible to write own validation layers for user-specific use cases. Focusing on finding potential issues as early and possible, and helping developers fixing them on very early project stages, Vulkan brings a new quality to the software development process.

Pic. 6. Validation layers in Vulkan application stack

# Example of debug message from the validation layervalidation layer: VkFence 0x1180000000118[] is in use. The Vulkan spec states: Each element of pFences must not be currently associated with any queue command that has not yet completed execution on that queue (https://www.khronos.org/registry/vulkan/specs/1.1-extensions/html/vkspec.html#VUID-vkResetFences-pFences-01123)

Considering we are free to extend this system even more by writing our validation layers, the software validation potential is now customizable as it was never before.

CPU offloading and GPU utilization

Sharing the GPU resources is very much present in modern automotive software designs. This, on its own, is a subject for a separate article. We can now point out a few main aspects:

  • Multiple device queues
  • Multiple physical devices

One of the main differences between OpenGL and Vulkan API is the fact that the second one gives us full support for multi-threaded rendering. We can now submit commands to GPU command queues from different threads. Nowadays, rendering systems architectures consider spreading the command upon multiple command queues having the synchronization entities in place to keep the relation between computation results in place. Vulkan also introduces a possibility to utilize more than one physical device at the same time. Due to these facts, we are now fully ready to utilize all GPU resources, and we can now free some of the CPU computing power. Speaking of CPU usage, the Vulkan execution model makes it possible to encapsulate graphics commands into so-called command buffers. We do not have to recreate these buffers each frame like it was the case for OpenGL. Command buffers can now be prepared in advance and stored in the GPU memory. They are accessible just like regular GPU side resources by using a handle. Another fact is that we can benefit from computing operations moving heavy computations to the GPU compute shaders, or optimize processing using transfer queues for memory transfer operations.

Pic. 7. Instrument Cluster rendered in real-time using Vulkan — Metal style with lights.

Summary

Looking at all the areas where Vulkan helps to improve GPU related development process, it looks like a way to go for the library and tools developers in the Automotive industry. When we have a predictable driver implementations and extendable internal error handling system, we will have validation possibilities never seen before. The sooner we take advantage of the new API, the sooner safety-critical applications development will be brought to the next level.

Pic. 8. Instrument Cluster rendered in real-time using Vulkan — retro style

Pic. 9. Instrument Cluster rendered in real-time using Vulkan — carbon style

Below you can find an example of PBR Instrument Cluster rendered in real-time using Vulkan API with following features:

  • Our shaders take advantage of Bidirectional Reflectance Distribution Function and calculate realistic lightning
  • We use using Image-Based Lighting (IBL) shaders to improve the realism of reflections
  • We use diffuse and specular Cube map construction in real-time
  • We generate mipmaps to make the color transition smooth for objects far away from the viewer
  • We use forward rendering technique because of scene simplicity
  • We are reducing the CPU usage by creating command buffers in advance and reusing them each frame
  • We use low poly meshes with high-resolution Textures 4K for high reflections quality
  • We are using MSAA x 8 multisampling to reduce aliasing

About the authors

Filip Wasil

A C++ passionate and OpenGL trainer at saferendering.com. Experienced in 3D performance optimization and UI development in frameworks like Kanzi, Unity or Unreal. I free time Filip develops his own open-source rendering engine.

Latest POSTS

June 17, 2020

What do the young think about cars in 2020

June 1, 2020

From an old Diesel to a Tesla as a new Driver

March 25, 2020

Automotive Instrument Cluster Prototype in Unreal Engine 4

February 5, 2020

What your face tells about you