Repository navigation
DisplayComposition
Status: WP0-WP4 and WP5.2-5.4 landed upstream (b72155e2bb, 2026-10-24), WP5.5 landed (8ded7e1869); WP5.1, 5.6 open (see section 4 and implementation-log.md) | Scope: AROS graphics subsystem, screen and window composition | Trees: rom/hidds/gfx, rom/graphics, rom/hyperlayers, rom/intuition, display drivers
This page defines the architecture for composition in AROS, the classes and interfaces that implement it, who owns each object and decision, and the phased work. It merges the screen-level composition proposal with the composited-layers (window-level) design, which share one compositor. Sections 2 and 3 describe the code as it is in the tree (2026-10-24); where the original design differs, the difference is stated in place.
-
Composition is a service of the Display. Every
Hidd_Displayobject owns a compositor. graphics.library and Intuition never talk to a compositor directly. - One compositor, two levels. The same compositor composes whole screens (ViewPorts) and composited layers (windows) inside them, through one request model.
- Hardware where possible, software where not. A display advertises scan-out planes with their constraints. The compositor assigns composition requests to planes and blits the remainder. The base Display is a one-plane display, so every existing driver keeps working unchanged.
- AmigaOS semantics are preserved. Simple, smart and super-bitmap windows behave as before. Composited and alpha windows are opt-in. The screen bitmap remains authoritative for code that addresses it directly. Classic chipset displays degrade to today's behaviour.
- No upward dependencies. The compositor does not open intuition.library. layers.library stays a geometry manager. Drivers never see Intuition or layers structures.
Intuition policy: which screens and windows exist,
|-- screens --> ViewPorts their order, position, opacity, flags
'-- windows --> Layers
|
layers.library geometry: visible/occluding shapes,
| composited-layer surfaces
v
graphics.library glue: builds HIDD_ViewPortData chains per
| display, carries CompositeRequests, owns
| framebuffer bookkeeping
v
+------------------ Hidd_Display (one per output) ---------------------------------+
| owns: DMEnum, Compositor, framebuffer, cursor, planes |
| |
| Hidd_Compositor (policy) Planes (mechanism, part of Hidd_Display) |
| base = hybrid plane/blit GetPlaneInfo / CommitPlanes / WaitLatch |
| driver may subclass base = one primary plane (== Show) |
+----------------------------------------------------------------------------------+
|
v
Hidd_Gfx (driver) blits: CopyBox, CopyBoxMasked, CopyBoxAlpha
| Object / decision | Owner | Created by | Lifetime |
|---|---|---|---|
Hidd_Display object |
driver (Hidd_Gfx subclass) |
driver New
|
driver |
Hidd_DMEnum |
Display | Display::New |
Display |
Hidd_Compositor object |
Display |
Display::New (driver class via aHidd_Display_CompositorClass, else base class) |
Display |
| Framebuffer bitmap | Display (attribute aHidd_Display_FrameBuffer), still created by graphics.library (display_FBCreate) when FrameBufferType != None; moving the creation into Display::New was not done |
graphics.library at display setup | Display |
| Plane set and constraints | Display (driver subclass) | static per hardware | Display |
| Composition policy (which request goes to which plane, what is blitted, mode policy) | Compositor | - | - |
| Screen stack, screen offsets, composition flags per screen | Intuition |
OpenScreen, ScreenPosition, RethinkDisplay
|
- |
| Window stack, layer shapes, composited-layer surfaces | layers.library | CreateLayerTagList |
layer |
Per-display HIDD_ViewPortData chain and its CompositeRequests |
graphics.library |
MakeVPort, LayerSurfacesChanged() from layers.library |
ViewPort / layer |
| Damage propagation | graphics.library -> Hidd_Display::UpdateRect -> its compositor's BitMapRectChanged
|
update_bitmap() |
- |
| Software cursor | Display | - | - |
Rules that follow:
-
graphics.library calls
HIDD_Display_*only.compositor_LoadViewPorts,compositor_ScrollBitMap,compositor_UpdateBitMap,DF_SoftComposit,compositor_Install/Setupand thedisplay_compositorfield are removed. -
The compositor is reached only through its Display. Nothing outside
rom/hidds/gfxand driver subclasses holds a compositor pointer. -
Drivers implement planes, not composition. A driver that composes in hardware describes planes; it does not implement
ShowViewPortsany more (kept for the transition only). -
Intuition supplies per-screen and per-window composition parameters as data (
VideoControltags on the ViewPort,LA_*tags on the layer), never by being queried.
Terminology: a surface is the bitmap of a composited layer (a window) presented inside its screen. An overlay is only ever a hardware plane type (vHidd_Plane_Overlay), never a window; the two words are not interchangeable anywhere in this plan.
A single request structure describes anything the compositor places on a display, whether a whole screen bitmap or a composited layer surface:
/* <hidd/gfx.h> */
struct HIDD_CompositeRequest
{
struct HIDD_CompositeRequest *Next; /* back to front within the parent */
OOP_Object *BitMap; /* HIDD bitmap object to show */
struct Rectangle Src; /* source rectangle in BitMap */
struct Rectangle Dest; /* destination in display pixels; != Src size = scale */
struct Region *Shape; /* display relative, NULL = Dest rectangle */
UBYTE Opacity; /* 0..255 constant alpha */
UBYTE AlphaMode; /* vHidd_CompAlpha_None | Fixed | PerPixel */
UWORD Flags; /* CRF_OPAQUE, CRF_PLANE_OK, CRF_PLANE_REQUIRED, CRF_SCALED */
ULONG ZOrder;
APTR UserData; /* compositor private */
};
struct HIDD_ViewPortData /* existing, extended */
{
struct HIDD_ViewPortData *Next;
OOP_Object *Bitmap;
struct ViewPortExtra *vpe;
APTR UserData;
OOP_Object *PreviousBitmap;
ULONG Flags;
/* new */
ULONG CompFlags; /* COMPF_* for this screen, from Intuition */
struct Hook *PreAlphaHook; /* SA_AlphaPreCompositingHook */
struct HIDD_CompositeRequest *Surfaces; /* composited layer surfaces of this screen */
};The screen itself is implicitly a request (Bitmap, DxOffset/DyOffset, CompFlags); surfaces (composited layers) are explicit requests relative to the screen. The compositor flattens both into one Z-ordered list per display.
-
Collect.
graphics.librarybuilds the per-displayHIDD_ViewPortDatachain (MakeVPort) and attaches each screen's surface list by reference (owned by the screen'sLayer_Info). -
Submit.
LoadView->HIDD_Display_ShowViewPorts(chain). A driver that composes in hardware itself returns TRUE; the base class returns FALSE, and graphics.library then callsHIDD_Display_ComposeViewPorts(chain), which hands the chain to the compositor (BitMapStackChanged). Position changes ->HIDD_Display_ViewPortPositionChange. Surface structure changes -> graphics' privateLayerSurfacesChanged()->HIDD_Display_SurfaceStackChanged. Content changes -> graphics'update_bitmap()->HIDD_Display_UpdateRect(method pointer cached per display) -> the compositor'sBitMapRectChanged. -
Decide. Screens only are candidates for planes; composited layer surfaces are always blended into the composed bitmap. The compositor gives the frontmost screens the overlay planes, highest z first, while each screen passes
HIDDCompositorPlaneFits()(format, scale range, alignment, size, never the framebuffer object, never a cursor plane). Z order is kept: once a screen gets no plane, every screen behind it is composed. The backmost screen always stays on the primary. Screens without a plane are drawn into the composed bitmap on the primary; when the first of them covers the display unscaled, without offset, alpha or surfaces, it is shown directly throughShow()(passthrough, zero copy).ENV:SYS/compositor.prefsNOPLANESturns plane use off. -
Commit.
HIDD_Display_CommitPlanes(states, count, flags)programs the overlay planes; the primary is driven byShow(). The DRM drivers apply the states one plane at a time (legacydrmModeSetPlane), not atomically. A refused commit currently switches planes off for the life of the Display (HIDDCompositorDisablePlanes); the compositor does not yet usefHidd_Commit_Testto fall back screen by screen (open, section 7). -
Report. The compositor answers
MapCoords, whichDisplayToBMCoords/BMToDisplayCoordscall, and reportsCOMPF_SCALEin its state when screens are scaled, so Intuition converts coordinates (SF_ScaledCoords).
Mode policy is a compositor attribute (aHidd_Compositor_ModePolicy), selected by the prefs: FollowTop (default, the display switches to the frontmost screen's mode), ScaleLargest (prefs SCALE: the display takes the mode of the largest screen shown and smaller screens are scaled up to it) and Native (prefs SCALE NATIVEMODE: the display keeps its own highest mode and every screen is scaled).
Interface and attribute names follow the existing gfx.conf conventions. New marks additions; Moved marks items relocated from elsewhere; Removed marks deletions.
Owner of composition for one output.
Attributes
| Attribute | Access | Status | Meaning |
|---|---|---|---|
aHidd_Display_Compositor |
.SG in gfx.conf
|
existing | the compositor object, created by New; Display::Set ignores it (owned by the display) |
aHidd_Display_CompositorClass |
I.. |
New | driver supplies a compositor subclass; default base class |
aHidd_Display_PlaneCount |
..G |
New | number of scan-out planes; base = 1 |
aHidd_Display_VBlankCount |
..G |
New | frame counter, 0 if unknown |
aHidd_Display_DisplayID |
.SG |
New | public display ID base, set by graphics.library at registration (the compositor reads it) |
aHidd_Display_CompositionCapabilities, CompositionState
|
..G, .SG
|
New | the compositor's Capabilities/State, for graphics.library (getdisplayinfodata.c) |
aHidd_Display_FrameBuffer |
.SG |
existing | unchanged |
aHidd_Display_DMEnumerator, GfxHidd, SpriteTypes, DPMSLevel, ConnectorType/ID, ... |
existing | unchanged |
Methods
| Method | Status | Base implementation |
|---|---|---|
ShowViewPorts(data) |
existing | base returns FALSE (does not compose in hardware); drivers that do return TRUE |
ComposeViewPorts(data, BOOL *composing) |
New | called by graphics.library when ShowViewPorts returned FALSE: the compositor's BitMapStackChanged
|
UpdateRect(bm, x, y, w, h) |
New | damage from graphics.library, forwarded to the compositor's BitMapRectChanged
|
ViewPortPositionChange(vpd, SIPTR *x, SIPTR *y) |
New | compositor validates and applies; returns TRUE if composing |
SurfaceStackChanged(vpd) |
New | compositor re-flattens that screen's surfaces |
GetPlaneInfo(ULONG idx, struct HIDD_PlaneInfo *, ULONG len) |
New | one primary plane: any displayable format, unity scale, opaque only |
CommitPlanes(struct HIDD_PlaneState *, ULONG count, ULONG flags) |
New | one plane: equivalent to Show(state[0].BitMap)
|
WaitLatch() |
New | returns immediately |
DisplayToBMCoords / BMToDisplayCoords
|
existing | the compositor's MapCoords (scaled screens), identity otherwise |
ModeProperties |
existing |
CompositionFlags filled from the compositor's capabilities |
Show(bitmap, flags) |
existing | kept as the one-plane commit primitive; drivers still override it |
SetCursorShape/Pos/Visible |
existing | base: software cursor in the Display; drivers with a hardware cursor override them and report it as a Cursor plane in GetPlaneInfo (never given to screens) |
MakeViewPort, InitViewPorts, DeinitViewPort
|
existing | unchanged (copper-list style hooks) |
Removed: the cached mid_CompositorSetCursorShape/Visible/Pos fields in HIDDDisplayData (gfx_display.h). They date from the 2026 split design, in which the Display was to delegate the software mouse pointer to its compositor and Display::Set cached the compositor's three cursor method IDs for the hot path. That delegation was never implemented: the merged tree renders the software cursor inside the Display class itself (the cursor_* functions in gfx_displayclass.c), the compositor interface has no cursor methods, and nothing reads the fields. The final architecture keeps the cursor a Display responsibility, backed by a Cursor plane where the hardware offers one, so the compositor will not own it later either. The fields are dead by design, not merely unused.
struct HIDD_PlaneInfo
{
ULONG Type; /* vHidd_Plane_Primary | vHidd_Plane_Overlay | vHidd_Plane_Cursor */
ULONG ZMin, ZMax;
ULONG PixFmtMask; /* bit per vHidd_StdPixFmt_* */
ULONG ScaleMin, ScaleMax; /* 16.16; 0x10000/0x10000 = unity only */
ULONG AlphaModes; /* bit per vHidd_CompAlpha_* */
UWORD PosAlignX, PosAlignY;
UWORD MaxWidth, MaxHeight;
ULONG Flags; /* PIF_NEEDS_DISPLAYMEM, PIF_FULL_WIDTH_ONLY, PIF_VSPLIT_ONLY */
};
struct HIDD_PlaneState
{
ULONG Plane;
OOP_Object *BitMap; /* NULL = disable */
struct Rectangle Src, Dest;
UBYTE Opacity;
UBYTE AlphaMode;
ULONG ZOrder;
};
/* CommitPlanes flags */
#define fHidd_Commit_NoWait (1 << 0)
#define fHidd_Commit_Test (1 << 1) /* validate only */The policy object. Base class is the hybrid plane/blit compositor: the former software compositor (Devs/Monitors/Compositor, now deleted) with its intuition.library dependency removed and plane assignment, scaling and composited-layer surfaces added. Drivers may subclass to override policy (planned for amigavideo's copper-list stacking, WP5.6).
Interface: hidd.gfx.compositor (IID_Hidd_Compositor) is kept. The single definition is the system header; the driver-private copies of the interface in nouveau, IntelGMA and amigavideo, which carried an older and incompatible method table under the same string, are gone: nouveau's and IntelGMA's private compositors are deleted (WP0.7, WP5.5), amigavideo's uses its own private interface name until WP5.6, so one IID means one method table.
Attributes
| Attribute | Access | Meaning |
|---|---|---|
aHidd_Compositor_DisplayHidd |
I.G |
owning Display |
aHidd_Compositor_DisplayID, FrameBuffer
|
..G |
read from the Display (no longer init tags) |
aHidd_Compositor_Capabilities |
..G |
COMPF_* the implementation can honour on this display (derived from planes + blit ability) |
aHidd_Compositor_State |
ISG |
enabled subset (prefs) |
aHidd_Compositor_ModePolicy |
ISG |
FollowTop / Native / ScaleLargest
|
aHidd_Compositor_BackFillHook |
ISG |
void-area fill |
aHidd_Compositor_Active |
..G |
TRUE when more than passthrough is in effect |
aHidd_Compositor_ComposedBitMap |
..G |
the blit target occupying the lowest plane, or NULL |
Methods
| Method | Role |
|---|---|
BitMapStackChanged(struct HIDD_ViewPortData *, BOOL *active) |
new chain; assign planes, redraw, commit |
SurfaceStackChanged(struct HIDD_ViewPortData *) |
surfaces of one screen changed |
BitMapPositionChange(OOP_Object *bm, SIPTR *x, SIPTR *y) |
validate/apply a screen offset |
BitMapRectChanged(OOP_Object *bm, x, y, w, h) |
damage on a bitmap; no-op for plane-scanned screens |
BitMapValidate(struct BitMap *), BitMapEnable(struct BitMap *)
|
custom screen bitmaps (existing) |
DisplayRectChanged(struct Rectangle *) |
kept as a mode-reselect hook (the planned DisplayChanged() rename was not done) |
MapCoords(OOP_Object *bm, BOOL toDisplay, LONG *x, LONG *y) |
New: display <-> screen coordinates for scaled screens |
Removed, and why:
-
aHidd_Compositor_DisplayIDandaHidd_Compositor_FrameBufferas init tags (done: both are now read-only and read from the Display). Before, graphics.library passes these because it creates the compositor and is the only party that knows the display's ID base and framebuffer object (compositor_Setup,graphics_compositor.c). Once the Display creates its own compositor (section 3.1), both values are the Display's own state: the framebuffer isaHidd_Display_FrameBuffer, and the ID base is needed only to allocate the composed bitmap with a valid DisplayID, which the compositor can request from its Display. Keeping them as tags would leave two sources of truth for values the Display already owns. -
GetAttr(SA_CompositingFlags, screen)andGetAttr(SA_AlphaPreCompositingHook, screen)inStackChanged. The compositor currently finds the IntuitionScreenbehind each bitmap and asks it for the per-screen flags and hook. That is an upward dependency from a HIDD onto Intuition, it only works for bitmaps that belong to a screen, and it is why the compositor has to open intuition.library at all. In the final model those values arrive as data inHIDD_ViewPortData.CompFlagsandPreAlphaHook, filled by graphics.library from the ViewPort (section 3.6), so any client that builds a View gets the same behaviour whether or not Intuition is involved. -
OpenLibrary("intuition.library"). With the two queries above gone, the compositor has no remaining use for Intuition. Dropping the open removes the only upward link fromgfx.hiddto Intuition, which is required for the class to live in ROM alongside graphics.library and to initialise before Intuition does (gfx.hidd resident priority 66 against Intuition's 15).
| Item | Status | Change |
|---|---|---|
UpdateRect |
existing, unchanged | damage reaches the compositor through Hidd_Display::UpdateRect (graphics.library calls the display, not the bitmap); the compositor calls the bitmap's UpdateRect where it shows the bitmap itself |
aHidd_BitMap_LeftEdge/TopEdge |
existing | remain the screen offset store |
aHidd_BitMap_Compositable, Displayable
|
existing | unchanged |
| Method | Status |
|---|---|
CopyBox, CopyBoxMasked
|
existing |
CopyBoxAlpha(src, sx, sy, dst, dx, dy, w, h, opacity, gc) |
Done (landed 2026-09). Correct source-over including destination alpha; drivers with accelerated PutAlphaImage get it for free |
A fourth layer kind, composited, alongside SIMPLE/SMART/SUPER. Private data:
struct IntLayer {
struct Layer lay;
struct Hook *shapehook;
IPTR window;
ULONG intflags; /* + INTFLAG_TRANSLUCENT (composited and blended: occludes nothing) */
struct RastPort rp;
struct BitMap *surface; /* composited surface, or LAYERS_BACKING_SURFACE backing store */
WORD surfw, surfh;
struct Region *occludeshape; /* what this layer hides from layers behind */
struct HIDD_CompositeRequest request; /* this layer's entry in the screen's surface list */
struct Region *compshape; /* request.Shape when the visible part is not the whole rectangle */
UBYTE opacity; /* 255 = opaque */
BOOL alphasurface;
ULONG alphaformat; /* PIXFMT_* of an alpha surface */
ULONG surfbytes; /* counted in the screen's surface budget */
};| Item | Status | Change |
|---|---|---|
LAYERS_BACKING_SURFACE |
Done (commit d37d20f52c, default off) | one layer-sized bitmap per smart layer; hidden ClipRects are views (CR_SHAREDBITMAP, CR_BMOFFX/Y) |
LAYERCOMPOSITED flag bit (Layer.Flags bit 3) |
New, public (graphics/clip.h) |
graphics.library needs it to pick the offset formula |
Tags LA_Composited, LA_Opacity, LA_AlphaSurface
|
Done (graphics/layersext.h, LA_AROS + 5..7) |
LA_SurfaceBitMap (caller-supplied surface) was not implemented |
SHAPEHOOKACTION_OPAQUEREGION |
not implemented | shape hook would declare the opaque sub-region of a translucent layer; translucent layers occlude nothing |
IsLayerHitAt(layer, x, y) LVO |
Done (layers 50.7) (after the six reserved MorphOS V52 slots that follow CollectPixelsLayer; MorphOS's own IsLayerHitable(layer) has a different signature and keeps its slot) |
alpha-aware hit test, also applied by WhichLayer()
|
| ClipRect contract for composited layers | New | exactly one hidden ClipRect covering bounds, BitMap = surface
|
occludeshape in the seven Z-walks |
New | translucent layers do not occlude |
| Presenter notifications | Done |
UPDATE_SURFACES() at the end of Create/Delete/MoveSize/MoveLayerZ/ChangeVisibility/ChangeShape rebuilds the screen's surface list and calls graphics' private LayerSurfacesChanged(screenbm, list); composited layers skip _BackupPartsOfLayer/_ShowPartsOfLayer pixel shuffling |
| Fallback | Done | display that cannot present surfaces (CompositeLayersSupported() FALSE), surface budget exceeded (4 x screen bitmap, 4 MB free floor) or allocation failure -> SMART at creation; growth that does not fit converts the layer in place (_UncompositeLayer) |
| Item | Status | Change |
|---|---|---|
display_LoadViewPorts |
shrink |
HIDD_Display_ShowViewPorts + framebuffer bookkeeping only |
ScrollVPort |
change | HIDD_Display_ViewPortPositionChange |
update_bitmap() |
shrink |
HIDD_BM_UpdateRect only |
graphics_compositor.c/.h, DF_SoftComposit, compositorClass, display_compositor
|
Removed | ownership moves to Display |
getdisplayinfodata.c DimensionInfo.reserved[0]
|
change | capabilities/state from aHidd_Compositor_Capabilities/State of the display's compositor, always |
VideoControl() |
Done |
VTAG_COMPOSITING_SET/GET, VTAG_ALPHAHOOK_SET/GET stored in ViewPortExtra, copied into HIDD_ViewPortData (CompFlags, PreAlphaHook, Surfaces) by MakeVPort
|
| Private LVOs for layers.library | Done (graphics 45.20) |
CompositeLayersSupported() (202), LayerSurfacesChanged() (203: stores the screen's surface list, HIDD_Display_SurfaceStackChanged), LayerSurfaceAlpha() (204: alpha of a surface pixel for hit tests) |
do_render_with_gc, do_pixel_func, MoveRaster, BltRastPortBitMap
|
change | layer-relative offset formula when LAYERCOMPOSITED
|
BltBitMapAlpha() |
Done public LVO 205 | application access to CopyBoxAlpha
|
MakeVPort |
unchanged |
| Item | Change |
|---|---|
OpenScreen |
writes SA_CompositingFlags/SA_AlphaPreCompositingHook to the ViewPort via VideoControl; SpecialFlags widened to ULONG so COMPF_SAME and future bits fit |
OpenWindow |
WA_Opaqueness (AmigaOS 4 name), WA_AlphaSurface -> LA_Opacity, LA_AlphaSurface, LA_Composited; composited windows report smart-refresh semantics for IDCMP_REFRESHWINDOW
|
| Hit testing |
WhichLayer applies the IsLayerHitAt policy for alpha-surface windows (transparent pixels fall through) |
SA_CompositingLayers, SA_OpacitySupport, SA_SourceAlphaSupport
|
DONE: report real values (CompositeLayersSupported(); source alpha only on 32-bit screens) |
| Monitor class |
DisplayToBMCoords/BMToDisplayCoords stay as the single coordinate path (PR 1639 COMPF_SCALE handling unchanged) |
| Appearance prefs |
SCALE and NATIVEMODE checkmarks (ENV:SYS/compositor.prefs template ABOVE/S,BELOW/S,LEFT/S,RIGHT/S,ALPHA/S,SCALE/S,NATIVEMODE/S,NOPLANES/S); absent variable = the AmigaOS default (ABOVE), an empty value disables composition |
| Driver | Final shape |
|---|---|
| All |
Hidd_Display subclass describes planes (default: none, base one-plane). ShowViewPorts overrides removed once the compositor is in place. |
| vcgfx (Pi, HVS) | (PR #1738 is the transitional ShowViewPorts form of this; see WP5.1) planes: primary (XRGB/RGB565, unity or upscale), overlay (32bpp, upscale, fixed/per-pixel alpha on HVS5+), cursor. CommitPlanes -> display-list author (hvs_build_list) + DISPLIST repoint; WaitLatch -> vc4_hvs_latch_wait. Private aHidd_VideoCoreGfxBitMap_Overlay retired; vc4gallium requests a plane through the public API. |
| vmwaresvga / amdgpu / nouveau (DRM) | overlay planes from drmModeGetPlaneResources; CommitPlanes -> legacy drmModeSetPlane per plane (atomic DRM_IOCTL_MODE_ATOMIC is routed in arosdrm.c but not used yet); cursor reported as a Cursor plane. nouveau's private compositor deleted. drm-aros enables universal planes for every client, so plane enumeration must filter on the plane type property (done in nouveau, still needed in amdgpu and vmwaresvga). |
| IntelGMA | private compositor retired onto the base hybrid (done: flip when the front screen covers the display, blit otherwise, through Show()). Planes (sprite/overlay per pipe, cursor) not yet described. |
| amigavideo |
Hidd_Compositor subclass keeps the copper-list stacking; planes report `PIF_VSPLIT_ONLY |
| Hosted X11 |
Done: two emulated overlay planes (child windows with the bitmap pixmap as background, XRender scaling up to 16x); --noplanes disables them. The SDL HIDD is SDL 1.2 based and not built. |
| vesagfx, vgagfx, efifb, fbgfx, p96gfx, sagagfx, sm502, linuxfb, wingdi | no changes; base one-plane display, software composition as today. |
Landed upstream 2026-10-24 as b72155e2bb (WP0-WP4, WP5.2-5.4 and the nouveau GB20x fixes; m68k ROM room made in aaab1ff30d); WP5.5 (IntelGMA) as 8ded7e1869. The m68k ROM-size measurement switches (
GFX_COMPOSITOR_STUB,AROS_NO_COMPOSITED_LAYERS) have been removed upstream as well.
Status key: DONE, WIP (in progress), TODO. Each package should leave both pc-x86_64 and linux-x86_64 building and the desktop smoke test passing.
| # | Task | Status |
|---|---|---|
| 0.1 |
Hidd_Gfx::CopyBoxAlpha with correct destination alpha; PutAlphaImage destination-alpha fix |
DONE |
| 0.2 | Software compositor blends via CopyBoxAlpha; ARGB custom screen bitmaps stamped in BitMapEnable
|
DONE |
| 0.3 | nouveau composes through the system compositor (NOUVEAU_PRIVATE_COMPOSITOR 0); verified on hardware |
DONE |
| 0.4 | OOP metaclass dispatch bounds-checks method IDs | DONE |
| 0.5 | layers: ClipRect content offsets, shared views, LAYERS_BACKING_SURFACE
|
DONE |
| 0.6 | Intuition COMPF_SCALE / SF_ScaledCoords coordinate conversion (PR 1639) |
DONE |
| 0.7 | Delete nouveau's private compositor source; rebase the IntelGMA and amigavideo compositor classes onto the system interface definition and make them non-public, so hidd.gfx.compositor has exactly one method table |
DONE (nouveau deleted; IntelGMA/amigavideo renamed to private interfaces hidd.gfx.compositor.intelgma / .amigavideo; IntelGMA's deleted in WP5.5) |
| 0.8 |
compositor_startup.c: test for the system class identity, not any class of that name (m68k double-start bug) |
DONE (program removed; AddDisplayDriverA() accepts and ignores an old binary) |
| 0.9 | Remove dead mid_CompositorSetCursor*; drop or implement DisplayRectChanged
|
DONE (fields removed; DisplayRectChanged kept as a mode-reselect hook) |
| 0.10 |
IntScreen.SpecialFlags -> ULONG; prefs: SCALE in mask, absent variable = off |
DONE: absent variable keeps the AmigaOS default (ABOVE); Appearance prefs writes an explicit empty value to disable; SCALE and NATIVEMODE checkmarks select the scaling policies (WP4.3) |
| 0.11 | Fix the layers defects listed in the study section 5 that touch this path (SA_BackFill never reaching the root layer, BeginRefresh EndUpdate on failure, CollectPixelsLayer slips) |
DONE (most were already fixed in HEAD; CollectPixelsLayer and a second ScreenDepth slip fixed) |
| # | Task |
|---|---|
| 1.1 |
Display::New attaches a compositor (aHidd_Display_CompositorClass / base class); aHidd_Display_Compositor read-only |
| 1.2 | Base ShowViewPorts routes to the compositor; passthrough -> Show
|
| 1.3 |
HIDD_Display_ViewPortPositionChange; ScrollVPort uses it |
| 1.4 | Damage goes to the Display's compositor (update_bitmap() -> Hidd_Display::UpdateRect); update_bitmap() reduced |
| 1.5 | Remove graphics_compositor.c/.h, DF_SoftComposit, compositor_Install/Setup; AddDisplayDriverA compositor magic removed; Devs/Monitors/Compositor deleted (AddDisplayDriverA and AROSMonDrvs ignore an old binary) |
| 1.6 |
getdisplayinfodata.c reads capabilities/state from the display's compositor |
| Acceptance | identical behaviour on VESA, VMware SVGA, nouveau, hosted X11; alphascreen and wpaaglobal pass; screen drag works |
WP2 - Compositor into gfx.hidd, no Intuition dependency - DONE (compositor class in gfx.hidd, VideoControl tags, no intuition.library)
| # | Task |
|---|---|
| 2.1 | Move compositor_class.c/displaymode.c to rom/hidds/gfx/gfx_compositorclass.c, genmodule class in gfx.conf
|
| 2.2 |
VideoControl tags for composition flags and pre-alpha hook; MakeVPort fills HIDD_ViewPortData.CompFlags/PreAlphaHook; compositor reads them instead of GetAttr(SA_*); drop intuition.library
|
| 2.3 |
aHidd_Compositor_ModePolicy (FollowTop only at this stage) |
| Acceptance | compositor builds in ROM for pc-x86_64; no intuition.library reference in gfx.hidd
|
WP3 - Composited layers (window level) - DONE including 3.3-3.6 (layers 50.7, graphics 45.20, intuition 50.19; runtime verified on pc-x86_64 and hosted X11; see implementation-log.md and wp3-remaining-notes.md)
| # | Task |
|---|---|
| 3.1 | Opaque composited layers: LAYERCOMPOSITED, single-ClipRect contract, graphics offset formula, LA_Composited; LayerSurfacesChanged() -> HIDD_Display_SurfaceStackChanged; surface nodes in the compositor drawn like alpha screens (opaque fast path: CopyBox + subtract from base redraw) |
| 3.2 | Test: CreateUpfrontLayerTagList composited layer on a screen, render, move, reorder. Criterion: MoveLayer performs zero BltBitMap in hyperlayers |
| 3.3 | Occlusion split (occludeshape), LA_Opacity, LA_AlphaSurface (screen-layout alpha surface, pens render transparent), IsLayerHitAt + WhichLayer policy |
| 3.4 | Intuition tags WA_Opaqueness, WA_AlphaSurface; SA_OpacitySupport etc.; refresh semantics |
| 3.5 | Memory budget per screen (4 x screen bitmap, 4 MB free floor) with automatic SMART fallback at creation and in-place conversion on growth |
| 3.6 |
BltBitMapAlpha() public API (graphics.library 45.20, LVO 205, AROS extension) |
| Acceptance | translucent window over a repainting window renders correctly; moving it generates no damage below; VESA, VMware, nouveau |
WP4 - Plane API and hybrid compositor - DONE (4.1-4.5; runtime verified on hosted X11 with two emulated, scaling overlay planes, see implementation-log.md)
| # | Task |
|---|---|
| 4.1 |
HIDD_PlaneInfo/HIDD_PlaneState, GetPlaneInfo, CommitPlanes, WaitLatch, aHidd_Display_PlaneCount/VBlankCount; base = one primary plane implemented via Show
|
| 4.2 | Hybrid assignment in the base compositor: frontmost screens on overlay planes by constraints, backmost screen always on the primary, the rest blitted into ComposedBitMap; BitMapRectChanged no-op for plane-scanned screens. Surfaces are not plane candidates. A refused commit disables planes for the Display (test-commit fallback open, section 7) |
| 4.3 | Scaling policies: prefs SCALE = display takes the largest shown screen's mode and smaller screens scale up to it (default scaling behaviour); SCALE NATIVEMODE = display keeps its own highest mode and every screen scales (user option). Scaling on planes or through the row-by-row software path; DisplayToBMCoords/BMToDisplayCoords answered by the compositor (MapCoords); COMPF_SCALE reported so Intuition converts coordinates |
| 4.4 | Cursor planes: drivers with a hardware cursor report it as a Cursor plane and keep driving it from their SetCursor* overrides; the base Display keeps the software cursor; the compositor never assigns screens to a cursor plane |
| 4.5 | Hosted plane emulation for validation: done in the X11 driver (child windows with the bitmap as background pixmap; the SDL HIDD is SDL 1.2 based and not built). --noplanes disables it |
| Acceptance | met with the X11 emulation: two screens -> two planes, third screen blitted; drag with scaling; existing tests unchanged on one-plane drivers |
WP5 - Driver bring-up - 5.2, 5.3, 5.4 landed (5.2 and 5.4 tested on hardware; see implementation-log.md "WP5" and "Hardware result 1-4"); 5.5 landed (8ded7e1869), not yet tested on hardware; 5.1, 5.6 open
| # | Driver | Task |
|---|---|---|
| 5.1 | vcgfx | WIP: PR #1738 (open, depends on #1725) already composes screens as HVS planes on VideoCore IV, HVS5 and HVS6 through ShowViewPorts, with scanout-memory screen bitmaps, vblank-latched commits, pointer-only flips, COMPF_SCALE and the coordinate hooks. Remaining for this plan: move the policy in vcgfx_planes.c/hvs_emit_planes (occlusion, backdrop, mode-follow-when-alone, 4-plane cap) into the compositor; expose the mechanism as GetPlaneInfo/CommitPlanes/WaitLatch; retire the private Overlay/VBlank/Flip bitmap attributes (vc4gallium via the public API); let screens beyond the plane budget and non-32bpp screens fall back to blit instead of being skipped |
| 5.2 | vmwaresvga | IMPLEMENTED: KMS plane layer (libdrm plane/flip/vblank wrappers, overlay enumeration, legacy SetPlane commits, vblank latch and counter), cursor plane, GetPlaneInfo/CommitPlanes/WaitLatch; vmwgfx has no overlay planes, so screens stay composed; scan-out screens behind VMWSVGA_PLANE_SCREENS. Hardware test (2026-10-22): works, planescreens PASS |
| 5.3 | amdgpu | IMPLEMENTED (builds, not tested on hardware): same KMS path as 5.2; overlay use needs screens in scan-out memory (AMDGPU_PLANE_SCREENS in amdgpu_kms.h, 0). Before turning it on, plane enumeration must keep overlay planes only (the plane type property, as in nouveau): with universal planes on, it would also take the primary and cursor planes. No vblank yet (DRM vblank code not built in this port) |
| 5.4 | nouveau | LANDED: screens are scanned out from their own buffer objects (HIDDNouveauEnsureFB), overlay planes (filtered by the plane type property) take the frontmost screens (drmModeSetPlane), cursor plane, real vblank (drm_vblank.c built; CommitPlanes waits a vblank only when it reprogrammed an overlay); nv04 YUV overlays excluded. GB207 (Blackwell, GSP, riscv64) verified with planescreens: overlay window, vblank and mode changes work after the riscv-nouveau session's fixes (window ownership on a live head with phywins, GB20x vblank enable and retrigger, CA7E colour defaults, opaque blending of XRGB, compat wait-entry init). NOUVEAU_WINDOW_PLANES=0 / NOUVEAU_WNDW_LIVE_OWNER=0 turn the Volta+ overlay windows off. Open: Xid 56 and GFW boot timeout at init. Pre-Volta overlays untested |
| 5.5 | IntelGMA | LANDED (8ded7e1869; builds and boots in QEMU without the card, not tested on Intel hardware): private compositor deleted. The Display no longer overrides ShowViewPorts, so the base compositor composes; Show() flips the plane base (SetFramebuffer) for a bitmap in the shown mode and loads the pipe timing (SwitchToVideoMode) otherwise. ModeProperties reports no hardware composition. A directly shown, scrolled oversized screen gets its new offsets in the plane base from BitMap::Set. Damage reaches the compositor through the display (graphics, cybergraphics), not through the bitmap class. No planes described yet (PlaneCount 1) |
| 5.6 | amigavideo | TODO: compositor subclass over copper lists; planes VSPLIT_ONLY; UAE testing |
| Test | Covers | Status |
|---|---|---|
Tests/graphics/alphascreen |
alpha screen composition, pixel-exact | DONE exists |
Tests/graphics/wpaaglobal |
WritePixelArrayAlpha global alpha |
DONE exists |
Tests/benchmarks/graphics/layerops, Tests/layers/newlayer
|
layers behaviour and performance | DONE exist |
Tests/layers/complayer, Tests/intuition/compwindow (WP3.2) |
surface rendering, zero-blit moves, opacity, per-pixel alpha | DONE exist |
Tests/layers/complayerhit, Tests/layers/compbudget, Tests/graphics/bltbitmapalpha, Tests/intuition/screendrag
|
alpha hit testing, surface budget and fallback, BltBitMapAlpha, screen dragging |
DONE exist |
Tests/intuition/planescreens + harness/hosted/xplanes (WP4) |
screen->plane mapping, fallback to blit, update through a plane | DONE exist; passes on hosted X11, QEMU VESA, VMware SVGA and the GB207 (nouveau, overlay window) |
Tests/intuition/pointerpos + harness/hosted/xpointer
|
COMPF_SCALE pointer coordinates on a scaled display |
DONE exists (hosted X11); drag bounds covered by planescreens under SCALE
|
Targets: VESA (QEMU), VMware SVGA, hosted X11, nouveau and amdgpu hardware, Raspberry Pi 3/4/5, UAE for amigavideo. Tested so far: QEMU VESA, hosted X11, VMware SVGA, nouveau GB207; amdgpu, Pi and UAE pending.
-
Memory. A composited window holds its surface while visible. Handled by the budget with fallback (WP3.5);
LAYERS_BACKING_SURFACEsurfaces are not budgeted. -
Direct screen-bitmap access. Programs drawing into
Screen->RastPortor locking the screen bitmap keep working because the screen bitmap remains the opaque base request. They cannot draw over composited layers; document this. -
Code that walks
Layer.ClipRect. Composited layers present one hidden ClipRect, the same view a fully obscured smart window gives today. Audit the few external users (muimaster, asl, gadtools). -
Plane counts and scaler limits on HVS (display-list RAM, line-buffer memory, Pi 5 UPM) and in KMS drivers are not static, but
PlaneFits()only checks the staticHIDD_PlaneInfolimits, and a refused commit switches planes off for good. AfHidd_Commit_Testloop that moves the backmost overlay screen into composition until the set is accepted is needed (section 7). -
Lock ordering. The presenter must never be entered with a layer lock held while the compositor may call back into graphics; the compositor calls only
Hidd_Gfxblits, which keeps this safe, but it must be stated as a rule. - Classic chipset. Composited layers are refused where the screen bitmap is the scan-out and no planes exist; the design degrades to today's behaviour.
- m68k ROM size. Resolved: with the compositor and composited layers enabled on every platform, the ROM fits after aaab1ff30d (genmodule startup helpers, string pools, packed boot image and more); GCC 6.5 leaves about 4.4 KB free in the main bank and 5.2 KB in the expansion bank. Further growth in either bank needs trimming or module moves.
-
Double/triple-buffered surfaces (MorphOS
LT_AllowDoubleBuffered) are a follow-on, not part of this plan. - Client overlays (GL, video). The plane API covers screens only. vcgfx keeps its client overlay pool driver-private for now and must count it when answering a test commit. The preferred public route is a composited layer whose surface is a scan-out buffer, which the compositor may promote to a plane; not decided.
Work that is open and self-contained: a fHidd_Commit_Test fallback loop in the compositor (after AssignPlanes, before ToggleCompositing; demote the backmost overlay screen until the set is accepted, keep DisablePlanes for real failures); atomic (property based) plane commits and page flips in the DRM drivers; overlay-only plane enumeration in amdgpu and vmwaresvga, then overlay scan-out of screens on amdgpu (AMDGPU_PLANE_SCREENS) on hardware; aspect-preserving (letterbox) scaling and a driver-declared preferred mode for the NATIVEMODE policy; budgeting LAYERS_BACKING_SURFACE smart-layer surfaces; ScaleLayer() for composited layers; describing IntelGMA's per-pipe sprite/overlay and cursor planes (GetPlaneInfo/CommitPlanes) and testing WP5.5 on Intel hardware.
Rules for contributions in this area:
- The presenter lives in the compositor, never in layers.library or Intuition.
- Hardware is reached only through
Hidd_Displayplanes; no driver-specific code above the Display. - Composited and alpha windows are opt-in; simple/smart/super semantics and memory footprint are unchanged unless asked for.
- Every change keeps
pc-x86_64andlinux-x86_64building and the existing graphics and layers tests passing. - AROS is a multi-architecture system. Anything that is not hardware register programming (plane assignment, scaling and mode policy, coordinate conversion, overflow fallback, vblank bookkeeping) is written once in
gfx.hiddor the compositor and must work for every architecture and driver: x86 and RISC-V PCI drivers, m68k Amiga, ARM and AArch64 boards, hosted targets. A driver contributes only the mechanism for its hardware, and that mechanism must not be gated on one CPU architecture when the hardware exists on more than one (the Pi 1-3 are 32-bit ARM and 64-bit AArch64 builds of the same VideoCore IV).
-
rom/hidds/gfx/gfx.conf,gfx_displayclass.c,gfx_display.h,include/gfx.h -
rom/hidds/gfx/gfx_compositorclass.c,gfx_compositor.h(the compositor, formerlyworkbench/devs/monitors/Compositor/) -
rom/graphics/graphics_display.c,getdisplayinfodata.c,scrollvport.c,updatebitmap.c,makevport.c,gfxfuncsupport.c,compositelayerssupported.c,layersurfaceschanged.c,layersurfacealpha.c,bltbitmapalpha.c -
rom/hyperlayers/layers_intern.h,basicfuncs.c,createlayertaglist.c,islayerhitat.c(surfaces, budget, hit test) -
arch/arm-native/soc/broadcom/2708/hidd/vcgfx/vcgfx_hvs*.{c,h}(HVS display lists) -
workbench/hidds/{vmwaresvga,amdgpu,nouveau}/libdrm/arosdrm.c,arosdrmmode.c(plane, flip and vblank wrappers);*_displayclass.c(GetPlaneInfo/CommitPlanes/WaitLatch) -
arch/all-hosted/hidd/x11/x11gfx_displayclass.c(plane emulation) - Commits:
d37d20f52c(layers backing surface),8a16cdb769(nouveau on the system compositor),aaab1ff30d(m68k ROM room),b72155e2bb(this plan's WP0-WP5.4),8ded7e1869(WP5.5 IntelGMA); PR #1639 (COMPF_SCALE) - Design notes: gfx HIDD Display/DMEnum split (2026-06), hyperlayers composition study (2026-09/10), display composition analysis (2026-10-18)