Graphics & rendering
AURA uses SDL3 for windows and input and Skia for 2D graphics and text. Its C++ scene graph connects layout, interaction, animation and media.
Graphics foundation
- C++20 and CMake provide native integration.
- Skia draws rounded rectangles, text through HarfBuzz/ICU, SVGs and images.
- Native GPU output and CPU-based offscreen rendering share the same scene graph.
- Libraries, versions and license texts are listed in Dependencies & licenses.
Structure
| File | Contents |
|---|---|
application.h |
Window, GL context, Skia GPU surface, event and rendering loop, offscreen PNG |
node.h |
Scene graph: Node, RectNode, ImageNode, SvgNode, TextNode, ScrollNode |
layout.h |
QML-like anchors (place(node).left(44).below(title, 30)), gridCell for grids |
animation.h |
Tweens with easing (Linear, InOutCubic, InOutQuint, OutQuad, OutBounce); bound to the target node, they stop when it is deleted |
resources.h |
Cache for images, SVGs and application-provided fonts |
video.h |
VideoPlayer (WebM/VP9, without audio, looping playlist) and VideoNode |
- Layouts: AURA now supports
Column,RowandGridin addition to explicit positions and anchors. See the language reference for details. - Logical resolution:
WindowOptionsdefines the logical size; the scene is scaled into the window for display. - Input:
- Tapping via
onTap - Dragging after 10 px on the nearest
ScrollNode - Flicking with deceleration and spring-back, similar to
Flickable(2500 px/s maximum, 1500 px/s² deceleration)
- Tapping via
- Clipping:
clipclips to a rectangle. Images can useradiusandroundedCornersfor their own rounded edges. - On-demand rendering: without an animation, the loop sleeps in
SDL_WaitEventTimeout.
Layout (aura/ui/layout.h)
QML anchors without bindings: a node is positioned once relative to its parent or a sibling node (same parent).
qml
Text title {
text: "AURA"
pixelSize: 28
place: left 44, top 44
}
Text subtitle {
text: "Application UI Runtime Architecture"
pixelSize: 18
place: left 44, below title 30
}
| Call | Meaning |
|---|---|
left/right/top/bottom(m) |
Distance to the parent's edge (right/bottom require the node's own size) |
centerX/centerY(offset), center() |
Centered in the parent, rounded to whole pixels like the old layouts |
below/above/rightOf/leftOf(sibling, spacing) |
Next to a sibling node |
alignLeft/alignTop/alignBottom(sibling), centerXOn/centerYOn(sibling) |
Aligned to a sibling node |
size(w, h) |
Set size (especially before right, bottom, and center) |
- Order matters: set the size first, then center or align to the right/bottom. The parent must already have its size at that point.
- Groups get their own container node, or an
Itemin AURA. gridCell(index, columns, w, h, spacingX, spacingY)returns a cell in a grid filled row by row (QMLGrid).Textderives its natural size from the content;wrap,fitandContext::fontSize()control wrapping and font sizes.Node::pressPositionis the press location (for ripples).Animation::onFinishedchains animations.- Buttons can use
Buttonor custom components;pressSinkadds pressed feedback. - Input:
aura::ui::InputDriver(input.h) acts as the finger on a scene: pressed state, tapping when released over the same node,onDrag, and dragging the nearestScrollNode.Applicationdrives one with the mouse;aura-viewuses its own. - Removal from a handler:
node->removeLater()immediately removes the node from the tree and deletes it before the next frame (Node::deleteRemoved(), called byApplication); a button can therefore close its own dialog.
Background work
aura::TaskRunner(aura/core/tasks.h) runs jobs on a small pool (processor count minus one, between 2 and 4 threads), cancelable throughstd::stop_token;stop(id)also stops a job that is still waiting.latest(slot, work, result)handles tasks where only the newest result matters (order lookup, the displayed photo): a new job on the sameaura::Lateststops the old one and discards its result, also aftercancel()or when the slot no longer exists. Editor thumbnails are decoded as a separate job per photo, in parallel.- Results return to the UI thread through
post(): the single UI-thread queue (aura::post()), processed by the application loop before every frame (aura::runPosted()). Callbacks belonging to a destroyedTaskRunnerare discarded. post()wakes the event loop throughApplication::wakeUp(). Without waking it, the result would arrive only at the 500-ms idle tick.- The destructor stops and joins all jobs. Callbacks therefore never outlive their owner.
Text
- Layout using SkParagraph and HarfBuzz/ICU.
TextNodesupports:- Alignment
HorizontalFit: reduces font size down tominimumPixelSize- Wrapping
- Simple rich text (
<b>,<br>, entities) - Styled runs (
setRuns: weight, italic, color, size) lineHeightas in QML (a multiplier of the font's line height). Qt places the extra spacing below each line. Skia distributes it, which is whykDisableFirstAscentand the adjustment inimplicitHeight()exist.
- If a font is missing characters, Skia searches system fonts through fontconfig on Linux for a replacement.
- Surfaces use grayscale antialiasing without gamma and contrast enhancement
(
SkSurfaceProps(0, kUnknown, 0, 1)). With Skia's defaults, white text on red appears significantly bolder than in Qt.
Video
VideoPlayerdemuxes with libwebm (mkvparser) and decodes with libvpx on a dedicated thread.- The queue holds 4 frames; the thread waits after that.
- libvpx decodes with up to 4 threads.
- The UI thread maintains a clock per file and displays each frame when due.
- Switching to the next file is a hard cut.
- The playlist loops indefinitely.
VideoNodeuploads I420 planes as three A8 textures (SkImages::TextureFromYUVAPixmaps). The GPU converts to RGB (BT.601 limited). Without a GPU, for example in screenshots, a simple CPU routine converts them.- The rendering loop is limited to 60 fps if the driver has no VSync.
- With
--debug, it logs fps every 5 s. - The player logs the number of displayed video frames per second.
- With
- Achievable frame rates depend on the device, graphics driver, scene and video.
Offscreen screenshots
Application::renderToPng(root, width, height, file) renders a scene to PNG without a window. The Hello example and gallery provide command-line entry points:
bash
build/dev/examples/hello/aura-hello --render hello.png
build/dev/examples/demo/aura-demo --render-all /tmp/aura-gallery
build/dev/tools/aura-view/aura-view examples/hello --render /tmp/hello.png
See aura-view for preview galleries and Testing for visual comparisons.
Documentation source:
docs/graphics.md Ā· Download Markdown