Skip to content

Tasks running in background

Michele edited this page Nov 17, 2019 · 3 revisions

Multithreading in the engine

As said in the game loop wiki page, it is not possible to do everything in the main loop.

In this page you will find a small description of what is executed in a background task using enkiTS scheduler.

Introduction

A "Command buffer" is a Vulkan object used to record commands which can be subsequently submitted to a device queue for execution.

Recorded commands include commands to bind pipelines and descriptor sets to the command buffer, commands to modify dynamic state, commands to draw (for graphics rendering), commands to dispatch (for compute), commands to execute secondary command buffers (for primary command buffers only), commands to copy buffers and images, and other commands.

For more see command buffer description.

Background tasks

Main Command Buffer

A normal and modern engine re-build the command buffer in background every frame, this allow to make a mesh appear/disappear when not visible or when added/deleted instantly.

This engine, for simplicity, use only two command buffers, the one current displayed and another one being re-built on background. This is less fast than rebuilding it every frame, and then meshes sometimes can take up to 1 or 2 frames before re-appearing when necessary.

Gui Command Buffer

A gui command buffer is necessary to register the gui draw commands.

The gui draw command couldn't be added to the main command buffer because there is a sync problem between the main loop that run on_gui() and the thread that re-build the main command buffer.

To avoid that, the gui has his own command buffer, that is re-built every frame. To avoid wasting too much time, a background task is started at the end of on_gui(), allowing it to re-build the gui command buffer while other updates (as the physics/audio update) execute. Obviosuly, before submitting it during draw_frame() the engine make sure the gui background task has ended.

Mesh cleanup

When the user delete a mesh, things are not easy as they might seems. The mesh data could still be on the current command buffer or in the one re-built in background waiting to be swapped with the current one.

To avoid this errors, every mesh has a flag, called "pending for deletion" and a "deletion counter". When the user un-register a mesh, it is flagged as "pending for deletion". In the meantime, everytime the main command buffer is re-built, if a mesh is "pending for deletion", the command buffer skip it (it doesn't draw it) and increase the "deletion counter".

Then, at the end of draw_frame(), when the current command buffer and the one built in background are swapped, a task in background is started. This task analyze all the meshes, and if a mesh is "pending for deletion", it check his "deletion counter". If the "deletion counter" is >= 2 i am sure there is not a command buffer using it, and i can safely delete the mesh from the heap memory. This task is waited before updating the render uniform_buffers, because is a cycle that need the meshes list.