Skip to content

Commit 7e3914a

Browse files
committed
09: the index moved the graphics stack to source builds
mcpplibs/mcpp-index#289 replaced the date-stamped versions with the upstream projects' own release numbers, and made compat.libdrm a source build. The example follows: libdrm 2026.08.30 -> 2.4.134 (now built from source) libgbm 2026.08.29 -> 25.0.7 (Mesa's version) egl 2026.08.30 -> 1.7.0 (libglvnd's version) The README's 'The packages' section said none of them vendors a source tree, which is no longer true, and the closure listing is re-measured against the published index. The interesting line is the first one: libdrm.so.2 resolves to the project's OWN build output rather than the payload copy Mesa was linked against — a soname already in the link map is reused, so the consumer's copy wins and Mesa's GBM allocates through it. That is why a library the payload also carries can still be built from source.
1 parent 90dfc5e commit 7e3914a

3 files changed

Lines changed: 104 additions & 42 deletions

File tree

examples/09-graphics-stack/README.md

Lines changed: 79 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -10,16 +10,29 @@ mcpp run
1010
```
1111
== the graphics stack, resolved from the index ==
1212
GBM_BACKENDS_PATH = …/subos/default/usr/lib/gbm
13-
wl_display_create 0x2e8d8be0
13+
wl_display_create 0x3f798be0
1414
-- DRM node -> GBM device -> EGL display --
1515
/dev/dri/renderD128
1616
drm driver nvidia-drm
17-
gbm_create_device 0x2e942f30
18-
eglGetPlatformDisplay 0x2e9bd390
17+
gbm_create_device 0x3f802f30
18+
gbm_bo_create (driver declined this format/usage)
19+
eglGetPlatformDisplay 0x3f87d5b0
20+
eglInitialize EGL 1.5, vendor Mesa Project
21+
/dev/dri/card0
22+
drm driver simpledrm
23+
gbm_create_device 0x3f802f30
24+
gbm_bo_create 256x256 stride=1024 modifier=0xffffffffffffff
25+
eglGetPlatformDisplay 0x3f87d5b0
1926
eglInitialize EGL 1.5, vendor Mesa Project
2027
done.
2128
```
2229

30+
That is one real run on a two-node machine, kept unabridged because the
31+
difference between the nodes is the point: `simpledrm` allocated the buffer and
32+
reported the driver's own stride and modifier, while NVIDIA's GBM backend
33+
declined that format/usage combination. Both are the libraries answering — this
34+
is the stack working, not a smoke test.
35+
2336
## What this example is for
2437

2538
System-level graphics work — a Wayland compositor, a Mesa-facing extension,
@@ -37,9 +50,9 @@ answer: the whole chain, done the recommended way, declaring dependencies.
3750

3851
```toml
3952
[target.'cfg(linux)'.dependencies.compat]
40-
libgbm = "2026.08.29"
41-
libdrm = "2026.08.30"
42-
egl = "2026.08.30"
53+
libdrm = "2.4.134"
54+
libgbm = "25.0.7"
55+
egl = "1.7.0"
4356
wayland = "2026.08.30"
4457
```
4558

@@ -48,29 +61,30 @@ That is the entire configuration. `src/main.cpp` then includes `<gbm.h>`,
4861
upstream APIs — nothing in it is mcpp-specific, so code written against these
4962
libraries anywhere else compiles here unchanged.
5063

51-
And it does the real thing rather than proving a symbol resolves: it opens
52-
`/dev/dri/renderD128`, builds a genuine `gbm_device` from that fd, hands it to
53-
`eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, …)` and initializes EGL against a
54-
real driver. A `gbm_create_device(-1)` on an invalid fd returns `NULL` and
55-
tells you nothing about whether the stack works; this reaches
56-
`EGL 1.5, vendor Mesa Project`.
64+
And it does the real thing rather than proving a symbol resolves: it opens a
65+
DRM node, builds a genuine `gbm_device` from that fd, **allocates actual GPU
66+
memory** with `gbm_bo_create` and reads back the stride and modifier the driver
67+
chose, then hands the device to
68+
`eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, …)` and initializes EGL. A
69+
`gbm_create_device(-1)` on an invalid fd returns `NULL` and tells you nothing
70+
about whether the stack works; this reaches `EGL 1.5, vendor Mesa Project`.
5771

5872
## Checking the claim
5973

60-
"Host-free" is easy to assert, so it is worth resolving the artifact's closure
61-
through the private loader it actually uses and looking at every path:
74+
"Host-free" is easy to assert, so resolve the artifact's closure through the
75+
private loader it actually uses and look at every path:
6276

6377
```bash
6478
BIN=target/x86_64-linux-gnu/*/bin/graphics-stack
6579
"$(readelf -p .interp $BIN | grep -o '/.*ld-linux[^ ]*')" --list $BIN
6680
```
6781

6882
```
69-
compat-x-egl/2026.08.30/…/libEGL.so.1
70-
compat-x-libdrm/2026.08.30/…/libdrm.so.2
71-
compat-x-libgbm/2026.08.29/…/libgbm.so.1
72-
compat-x-wayland/2026.08.30/…/libwayland-client.so.0
73-
compat-x-wayland/2026.08.30/…/libwayland-server.so.0
83+
<project>/target/.../bin/libdrm.so.2 <- built from source, by this build
84+
compat-x-libgbm/25.0.7/…/libgbm.so.1
85+
compat-x-egl/1.7.0/…/libEGL.so.1
86+
compat-x-wayland/…/libwayland-client.so.0
87+
compat-x-wayland/…/libwayland-server.so.0
7488
xim-x-expat/2.6.2/lib/libexpat.so.1
7589
xim-x-gcc/16.1.0/lib64/libgcc_s.so.1
7690
xim-x-glibc/2.44/lib64/libc.so.6
@@ -79,29 +93,55 @@ xim-x-libffi/3.4.4/lib/libffi.so.8
7993
xim-x-libglvnd/1.7.0.1/lib/libGLdispatch.so.0
8094
```
8195

82-
Every entry is under the registry; none is under `/usr/lib` or `/lib64`. Note
83-
the bottom half especially — `libexpat`, `libffi` and `libGLdispatch` are
84-
*transitive*: nothing in `mcpp.toml` names them. They are what a directly
85-
linked `libgbm.so.1` cascades into, and resolving that cascade is exactly what
86-
the host path cannot do from inside a private loader. Declaring the four
87-
dependencies resolved all eleven.
96+
Nothing is under `/usr/lib` or `/lib64`. Two things in that list are worth
97+
reading closely.
98+
99+
**The first line.** `libdrm.so.2` resolves to this project's own build output,
100+
not to the `xim-x-libdrm` the Mesa payload was linked against — even though
101+
`libgbm.so.1` has a DT_NEEDED on that soname and an absolute RUNPATH pointing
102+
into the payload. The consumer links libdrm directly, so it is mapped first,
103+
and Mesa's GBM binds to it: the `gbm_bo_create` above ran through it.
104+
105+
**The bottom half.** `libexpat`, `libffi` and `libGLdispatch` are *transitive*
106+
nothing in `mcpp.toml` names them. They are what a directly linked
107+
`libgbm.so.1` cascades into, and resolving that cascade is exactly what a host
108+
`-L/usr/lib` cannot do from inside a private loader.
88109

89110
## The packages
90111

91-
None of them vendors a source tree. Mesa, libdrm, libglvnd and wayland are
92-
already in the ecosystem (`xim:mesa`, `xim:libdrm`, `xim:libglvnd`,
93-
`xim:wayland`), so each package is a thin binding: it declares the ecosystem
94-
package it needs and exposes that payload's headers and libraries to the
95-
compiler. Building second copies would put two `libgbm.so.1` — or two
96-
`libdrm.so.2`, or a second EGL dispatch library — in a process that already
97-
loads Mesa's.
98-
99-
| package | what it gives you |
100-
|---|---|
101-
| `compat.libgbm` | `gbm_create_device`, `gbm_bo_create` — buffers out of a DRM device |
102-
| `compat.libdrm` | `drmModeGetResources`, `drmModeAddFB2`, `drmModeSetCrtc` — the KMS side |
103-
| `compat.egl` | `eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, …)` — rendering onto them |
104-
| `compat.wayland` | client and server libraries for the display protocol |
112+
Two of them are built from source and two bind the ecosystem's Mesa, and the
113+
split is not arbitrary. A library is built from source when upstream ships it
114+
as a **separable unit**; it is bound when it is an internal build target of a
115+
project the ecosystem already owns, where building it would mean forking that
116+
project.
117+
118+
| package | | what it gives you |
119+
|---|---|---|
120+
| `compat.libdrm` | source | `drmModeGetResources`, `drmModeAddFB2`, `drmModeSetCrtc` — the KMS side |
121+
| `compat.libgbm` | binds `xim:mesa` | `gbm_create_device`, `gbm_bo_create` — buffers out of a DRM device |
122+
| `compat.egl` | binds `xim:libglvnd` | `eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, …)` — rendering onto them |
123+
| `compat.wayland` | binds `xim:wayland` | client and server libraries for the display protocol |
124+
125+
libdrm passes the test — an independent freedesktop project with its own
126+
releases — so it is compiled here, five translation units with no dependencies
127+
at all. GBM fails it: `src/gbm/meson.build` is `link_with: [libloader]`, and
128+
`libloader` wants `idep_mesautil`, roughly 120 TUs of Mesa's internal utility
129+
library for one function. It is also a *loader*, and the backends it dlopens
130+
are Mesa's own, so built apart from Mesa it would have nothing to load.
131+
132+
**A payload carrying the same library is not a reason to bind**, which is worth
133+
saying because it looks like one. Mesa's `libgbm.so.1` has a DT_NEEDED on
134+
`libdrm.so.2` and an absolute RUNPATH into the payload's copy — and in this
135+
program that RUNPATH loses. A soname already in the link map is reused, so
136+
ld.so never searches for it again: the `libdrm.so.2` this project linked is
137+
mapped first, exactly one is loaded, and Mesa's GBM allocated the buffer above
138+
through it. That only holds because the package builds a *shared* library with
139+
the canonical soname; merged into the consumer as objects there would be two
140+
copies of libdrm's internal state over one set of file descriptors.
141+
142+
`compat.egl` is a binding for a duller reason: libglvnd IS separable, but
143+
`libEGL.so` also needs its Python-generated dispatch stubs, `winsys_dispatch`
144+
and the whole of `libGLdispatch.so`, so it has not been done yet.
105145

106146
One honest gap, since "Mesa/Vulkan" usually get named together: Vulkan is not
107147
part of this example and is not in the same state. `compat.vulkan-runtime`

examples/09-graphics-stack/mcpp.toml

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,17 @@ name = "graphics-stack"
33
version = "0.1.0"
44

55
# The whole KMS/DRM stack, from the index. No host paths, no -L/usr/lib.
6+
#
7+
# The versions are the upstream projects' own release numbers, and two of these
8+
# packages are BUILT FROM SOURCE here while two bind the ecosystem's Mesa. The
9+
# split is not arbitrary: a library is built from source when upstream ships it
10+
# as a separable unit, and bound when it is an internal target of a project the
11+
# ecosystem already owns. libdrm passes that test; GBM does not — it is a build
12+
# target inside Mesa, and a loader whose backends are Mesa's own.
613
[target.'cfg(linux)'.dependencies.compat]
7-
libgbm = "2026.08.29" # buffer allocation out of a DRM device
8-
libdrm = "2026.08.30" # the KMS side: modes, CRTCs, framebuffers
9-
egl = "2026.08.30" # rendering onto those buffers
14+
libdrm = "2.4.134" # source-built; the KMS side: modes, CRTCs, framebuffers
15+
libgbm = "25.0.7" # Mesa's GBM: buffer allocation out of a DRM device
16+
egl = "1.7.0" # libglvnd's EGL dispatch: rendering onto those buffers
1017
wayland = "2026.08.30" # the display protocol, client and server
1118

1219
# compat.wayland puts only -lwayland-client on the link line, because a

examples/09-graphics-stack/src/main.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,21 @@ int main()
8383
if (gbm_device *gbm = gbm_create_device(fd)) {
8484
report("gbm_create_device", gbm);
8585

86+
// Actually allocate GPU memory. Creating the device only proves the
87+
// backend loaded; a buffer object is the thing a compositor hands
88+
// to drmModeAddFB2 for scanout, and its stride and modifier come
89+
// back from the driver rather than from libgbm.
90+
if (gbm_bo *bo = gbm_bo_create(gbm, 256, 256, GBM_FORMAT_XRGB8888,
91+
GBM_BO_USE_RENDERING)) {
92+
std::printf(" %-24s 256x256 stride=%u modifier=0x%llx\n",
93+
"gbm_bo_create", gbm_bo_get_stride(bo),
94+
(unsigned long long)gbm_bo_get_modifier(bo));
95+
gbm_bo_destroy(bo);
96+
} else {
97+
std::printf(" %-24s (driver declined this format/usage)\n",
98+
"gbm_bo_create");
99+
}
100+
86101
EGLDisplay dpy =
87102
eglGetPlatformDisplay(EGL_PLATFORM_GBM_KHR, gbm, nullptr);
88103
report("eglGetPlatformDisplay", dpy);

0 commit comments

Comments
 (0)