<alp/gpu2d.h> — 2D Graphics Acceleration
Portable 2D blit / fill / blend operations against framebuffer surfaces.
Zephyr has no portable 2D-accelerator driver class, and the Alif Ensemble parts carry a hardware 2D engine. Without a portable surface, a customer migrating from V2N to AEN would silently lose that acceleration. This header exists so customer code compiles — and runs — on every SoM, taking the hardware path where one exists and a CPU path everywhere else.
Header
#include <alp/gpu2d.h>
Quick example
alp_gpu2d_t *g = alp_gpu2d_open();
const alp_gpu2d_surface_t fb = {
.base = framebuffer,
.width = 800,
.height = 480,
.stride_bytes = 800 * 4,
.format = ALP_GPU2D_FMT_ARGB8888,
};
alp_gpu2d_fill_rect(g, &fb, 10, 10, 100, 50, 0xFFFF0000); // red
alp_gpu2d_close(g);
Which SoMs have GPU2D silicon?
The 2D engine on the Alif Ensemble is the TES D/AVE 2D block (Alif markets it as "GPU2D"). Per the SoC metadata, it is present on exactly three Ensemble SKUs:
| SoM | SoC | 2D silicon? |
|---|---|---|
| E1M-AEN601 | Alif Ensemble E6 | ✅ D/AVE 2D |
| E1M-AEN701 | Alif Ensemble E7 | ✅ D/AVE 2D |
| E1M-AEN801 | Alif Ensemble E8 | ✅ D/AVE 2D |
| E1M-AEN301 / AEN401 / AEN501 | Ensemble E3 / E4 / E5 | ❌ |
| E1M-V2N101/102, E1M-V2M101/102 | Renesas RZ/V2N | ❌ |
| E1M-NX9101 | NXP i.MX 93 | ❌ — the i.MX 93's 2D engine is PXP, which is not a GPU2D peer (see ADR 0008) and is not wired to this surface |
ALP_HAS(GPU2D) / ALP_HAS(DAVE2D) from <alp/cap.h> are the portable way to ask.
:::caution The hardware backend is bench-unverified today
The D/AVE 2D backend is structural. It is authored against the documented d2_* driver API and the D/AVE 2D programming model — no hardware register value or address is invented — but it has not been compiled against the real vendor pack and has not been run on AEN silicon. Call sequencing, format/blend-mode mappings, and the submit-and-wait flush model are a first cut to be confirmed at bench bring-up. Cache maintenance against the caller's framebuffer is a documented follow-up, not yet implemented.
It is also gated behind CONFIG_ALP_SDK_GPU2D_ALIF_DAVE2D, which the build sets only when Alif's proprietary D/AVE 2D driver pack (AlifSemiconductor::Dave2DDriver) is on the include path. That pack is pulled at build time and is not vendored into the SDK.
In practice: unless you have explicitly supplied that pack, the software fallback is what runs — on every SoM, including AEN. Treat hardware acceleration here as not yet available. :::
Backends
| Backend | silicon_ref | Priority | Status |
|---|---|---|---|
dave2d_e6 / dave2d_e7 / dave2d_e8 | "alif:ensemble:e6" / "e7" / "e8" | 100 | Bench-unverified; requires the proprietary pack. Advertises ALP_INSTANCE_CAP_DMA. |
sw_fallback | "*" | 0 | The backend that actually runs and is tested (on native_sim). Portable CPU fill/blit/blend. |
One D/AVE 2D row per SKU that actually carries the engine, at priority 100 so the registry prefers it over the wildcard fallback on those parts only — see the selection rules. With the pack absent, those rows are not compiled at all and the priority-0 wildcard wins everywhere.
The software fallback is what V2N, i.MX 93, and ALP_OS=yocto Linux builds use, and it implements all five pixel formats.
Plain-CMake bare-metal builds are the exception: there is no backend registry on that path yet, so they link a NOSUPPORT stub — alp_gpu2d_open() returns NULL with ALP_ERR_NOSUPPORT and every op returns ALP_ERR_NOSUPPORT.
Functions
| Call | Returns |
|---|---|
alp_gpu2d_open(void) | alp_gpu2d_t *, or NULL with alp_last_error() set. With the software fallback enabled (the default, CONFIG_ALP_SDK_GPU2D_SW_FALLBACK) open succeeds on every SoM — there is no NOSUPPORT case at open time. NULL means either no backend compiled in at all (ALP_ERR_NOT_PRESENT_ON_THIS_SOC) or the handle pool is exhausted (ALP_ERR_NOMEM). |
alp_gpu2d_fill_rect(handle, dst, x, y, w, h, argb_color) | ALP_OK / ALP_ERR_NOT_READY / ALP_ERR_INVAL / ALP_ERR_OUT_OF_RANGE / ALP_ERR_NOSUPPORT. Rect is clipped to dst's dimensions. |
alp_gpu2d_blit(handle, src, sx, sy, dst, dx, dy, w, h) | Same set. Copy with no blend; converts format when src->format != dst->format and both are in the backend's supported set, else ALP_ERR_NOSUPPORT. |
alp_gpu2d_blend(handle, src, sx, sy, dst, dx, dy, w, h, mode) | Same set. Alpha-blends per mode. |
alp_gpu2d_close(handle) | void. NULL is a no-op. |
alp_gpu2d_capabilities(const alp_gpu2d_t *handle) | const alp_capabilities_t *, valid for the handle's lifetime; NULL handle → NULL. See instance capabilities. |
:::note The handle pool defaults to ONE
The 2D engine is a system-wide singleton, so a second alp_gpu2d_open() before alp_gpu2d_close() fails with ALP_ERR_NOMEM rather than aliasing the live handle. The pool size is the CONFIG_ALP_SDK_MAX_GPU2D_HANDLES compile-time override — there is no Kconfig entry for it today; define it on the build.
:::
The colour passed to fill_rect is always ARGB8888 and the backend converts: RGB565 ignores the high 16 bits, A8 takes only the high byte (alpha).
Concurrency
The singleton handle is reentrant under a shared driver mutex, but callers must serialise fill_rect / blit / blend issuance themselves — the software fallback writes caller memory directly, and the D/AVE 2D HAL's display-list builder is not itself thread-safe.
Blit overlap contract
Pixels are processed top-to-bottom, left-to-right. An overlapping same-buffer copy toward earlier memory (dy < sy, or dy == sy with dx <= sx) is safe. A copy toward later memory may read pixels the op already wrote — backends do not reverse-iterate. Callers needing overlap-safe moves in both directions must use distinct buffers.
Surface descriptor
alp_gpu2d_surface_t lives in caller memory and is copied internally per operation, so you can reuse or modify the struct between calls.
| Field | Type | Notes |
|---|---|---|
base | void * | Pointer to the top-left pixel (no header byte). |
width / height | uint32_t | Dimensions in pixels. |
stride_bytes | uint32_t | Bytes from one row's start to the next (= width * bytes-per-pixel when tightly packed). |
format | alp_gpu2d_format_t | See below. |
Pixel formats
Backends honour the subset their hardware supports; unsupported formats return ALP_ERR_NOSUPPORT.
| Format | Layout |
|---|---|
ALP_GPU2D_FMT_ARGB8888 | 32-bit, A:R:G:B = 8:8:8:8 (the D/AVE 2D default) |
ALP_GPU2D_FMT_RGB565 | 16-bit, R:G:B = 5:6:5 |
ALP_GPU2D_FMT_A8 | 8-bit alpha only — useful for masks |
ALP_GPU2D_FMT_RGB888 | 24-bit packed; backend-defined byte order |
ALP_GPU2D_FMT_RGBA8888 | 32-bit, R:G:B:A = 8:8:8:8 (alternate ordering) |
Blend modes
Colours are straight (non-premultiplied) alpha.
| Mode | Formula |
|---|---|
ALP_GPU2D_BLEND_REPLACE | dst = src (no blend) |
ALP_GPU2D_BLEND_SRC_OVER | dst = src*src.a + dst*(1-src.a) — a transparent src leaves dst untouched; an opaque src replaces it |
ALP_GPU2D_BLEND_ADDITIVE | dst = src + dst (clamped) |
ALP_GPU2D_BLEND_MULTIPLY | dst = src * dst |
ABI status
[ABI-EXPERIMENTAL] — new in v0.5 (AEN audit headline gap). A portable surface, but only one silicon family populates it today. Pin your SDK to a specific commit if you depend on it.
See also
<alp/display.h>— the display subsystem that owns the framebuffer<alp/gui.h>— LVGL with Alp defaults<alp/cap.h>—ALP_HAS(GPU2D)/ALP_HAS(DAVE2D)gating<alp/backend.h>— why the fallback wins when the pack is absent