| # Debug Overlay in ANGLE's Vulkan Backend | |
| ## Motivation | |
| A complex application has frequently changing performance characteristics due to | |
| both a varying number of objects to draw and different effects that need to be | |
| applied to them. When characterizing the performance of an application, it can | |
| be easy to miss scenes which need optimization, especially if they are | |
| ephemeral. | |
| A debug overlay that shows on-the-fly statistics from the running application | |
| can greatly aid the developer in finding where the bottlenecks are and which | |
| scenes need further investigation and profiling. | |
| ANGLE's Vulkan debug overlay implements this. The initial implementation | |
| includes a few pieces of information for demonstration purposes. Here's the | |
| glmark2 *terrain* scene with these overlay items enabled: | |
|  | |
| This is a screenshot of a debug build, hence the low FPS. The command graph size | |
| widget no longer applies to current ANGLE code. | |
| ## Implementation | |
| Overlay items are of two fundamental types: | |
| * Text items: A single line of text with small or large font. | |
| * Graph items: A bar graph of data. These each have a Text item attached | |
| that is automatically rendered with the graph item. | |
| Built on these, various overlay item types are defined that gather statistics. | |
| Five such types are defined with one item per type as example: | |
| * **Count**: An item that counts something. **VulkanValidationMessageCount** | |
| is an overlay item of this type that shows the number of validation messages | |
| received from the validation layers. | |
| * **Text**: A generic text widget. **VulkanLastValidationMessage** is an overlay | |
| item of this type that shows the last validation message. | |
| * **PerSecond**: A value that gets reset every second automatically. **FPS** is | |
| an overlay item of this type that simply gets incremented on every `swap()`. | |
| * **RunningGraph**: A graph of the last N values. **VulkanRenderPassCount** is an | |
| overlay of this type. This counter reports the number of RenderPasses rendered | |
| in each vkQueueSubmit call. | |
| * **RunningHistogram**: A histogram of last N values. Input values are in the | |
| [0, 1] range and they are ranked to N buckets for histogram calculation. | |
| **VulkanSecondaryCommandBufferPoolWaste** is an overlay item of this type. | |
| On `vkQueueSubmit()`, the memory waste from command buffer pool allocations | |
| is recorded in the histogram. | |
| Overlay font is placed in [libANGLE/overlay/](../src/libANGLE/overlay/) which | |
| [gen_overlay_fonts.py](../src/libANGLE/gen_overlay_fonts.py) processes to create | |
| an array of rasterized font data, which is used at runtime to create the font | |
| image (an image with one layer per character, and one mip level per font size). | |
| The overlay widget layout is defined in | |
| [overlay_widgets.json](../src/libANGLE/overlay_widgets.json) | |
| which [gen_overlay_widgets.py](../src/libANGLE/gen_overlay_widgets.py) | |
| processes to generate an array of widgets, each of its respective type, | |
| and sets their properties, such as color and bounding box. | |
| The json file allows widgets to align against other widgets as well as against | |
| the framebuffer edges. The following is a part of this file: | |
| ```json | |
| { | |
| "name": "VulkanValidationMessageCount", | |
| "type": "Count", | |
| "color": [255, 0, 0, 255], | |
| "coords": [10, "VulkanLastValidationMessage.top.adjacent"], | |
| "font": "small", | |
| "length": 25 | |
| }, | |
| { | |
| "name": "VulkanSecondaryCommandBufferPoolWaste", | |
| "type": "RunningHistogram(50)", | |
| "color": [255, 200, 75, 200], | |
| "coords": [-50, 100], | |
| "bar_width": 6, | |
| "height": 100, | |
| "description": { | |
| "color": [255, 200, 75, 255], | |
| "coords": ["VulkanSecondaryCommandBufferPoolWaste.left.align", | |
| "VulkanSecondaryCommandBufferPoolWaste.top.adjacent"], | |
| "font": "small", | |
| "length": 40 | |
| } | |
| } | |
| ``` | |
| Negative coordinates in this file indicate alignment to the right/bottom of the | |
| framebuffer. `OtherItem.edge.mode` lets an item be aligned with another. | |
| If `mode` is `align`, the item has the same origin as `OtherItem` and expands | |
| in the same direction. If `adjacent`, the item expands in the opposite | |
| direction. | |
| The UI is rendered in two passes, one draw call for all graph widgets and | |
| another draw call for all text widgets. The vertex shader in these draw calls | |
| generates 4 vertices for each instance (one instance per widget) based on the | |
| widget bounding box. The fragment shader renders font or a graph based on widget | |
| data. This is done once per frame on `present()`, and the result is blended into | |
| the swapchain image. | |
| To build ANGLE with overlay capability, `angle_enable_overlay = true` must be | |
| placed in `args.gn`. | |
| Currently, to enable overlay items an environment variable is used. For example: | |
| On Desktop: | |
| ```commandline | |
| $ export ANGLE_OVERLAY=FPS:Vulkan*PipelineCache* | |
| $ ./hello_triangle --use-angle=vulkan | |
| ``` | |
| On Android: | |
| ``` | |
| $ adb shell setprop debug.angle.overlay FPS:Vulkan*PipelineCache* | |
| $ ./hello_triangle --use-angle=vulkan | |
| ``` | |
| ## Future Work | |
| Possible future work: | |
| * On Android, add settings in developer options and enable items based on those. | |
| * Spawn a small server in ANGLE and write an application that sends | |
| enable/disable commands remotely. | |
| * Move the Overlay rendering functionality to the front-end to benefit all | |
| backends. | |
| * Add more overlay widgets. | |
| * Implement automatic widget layout to remove the need to specify positions in | |
| the overlay widgets JSON. |